為什么Flutter會選擇 Dart ?

PHP技術大全 / 2019-03-15 15:00:38

許多語言學家認為,一個人說的自然語言會影響他們的思維方式。這個理論適用于計算機語言嗎?使用不同編程語言編程的程序員針對問題想出的解決方案經常完全不同。舉一個極端的例子,為了程序結構更加清晰,計算機科學家取消了goto語句(這與小說《1984》中的極權主義領導者從自然語言中刪除異端詞語以消除思維犯罪不太一樣,但道理就是這樣)。

這與Flutter和Dart有什么關系?確實有關系。早期的Flutter團隊評估了十多種語言,并選擇了Dart,因為它符合他們構建用戶界面的方式。

Dart是開發人員喜歡Flutter的一大原因。如以下推文:

@flutterio got me to look at @dart, and I’m glad I took it for a spin. #Dart is an awesome language, and #flutterio takes it even further, to mobile devices <3

以下是使Dart成為Flutter不可或缺的一部分的特性:

  • Dart是AOT(Ahead Of Time)編譯的,編譯成快速、可預測的本地代碼,使Flutter幾乎都可以使用Dart編寫。這不僅使Flutter變得更快,而且幾乎所有的東西(包括所有的小部件)都可以定制。

  • Dart也可以JIT(Just In Time)編譯,開發周期異常快,工作流顛覆常規(包括Flutter流行的亞秒級有狀態熱重載)。

  • Dart可以更輕松地創建以60fps運行的流暢動畫和轉場。Dart可以在沒有鎖的情況下進行對象分配和垃圾回收。就像JavaScript一樣,Dart避免了搶占式調度和共享內存(因而也不需要鎖)。由于Flutter應用程序被編譯為本地代碼,因此它們不需要在領域之間建立緩慢的橋梁(例如,JavaScript到本地代碼)。它的啟動速度也快得多。

  • Dart使Flutter不需要單獨的聲明式布局語言,如JSX或XML,或單獨的可視化界面構建器,因為Dart的聲明式編程布局易于閱讀和可視化。所有的布局使用一種語言,聚集在一處,Flutter很容易提供高級工具,使布局更簡單。

  • 開發人員發現Dart特別容易學習,因為它具有靜態和動態語言用戶都熟悉的特性。

并非所有這些功能都是Dart獨有的,但它們的組合卻恰到好處,使Dart在實現Flutter方面獨一無二。因此,沒有Dart,很難想象Flutter像現在這樣強大。


本文接下來將深入探討使Dart成為實現Flutter的最佳語言的許多特性(包括其標準庫)。

編譯和執行

[如果你已經了解靜態語言與動態語言、AOT與JIT編譯以及虛擬機等主題,可以跳過本節。]

歷史上,計算機語言分為兩組:靜態語言(例如,Fortran和C,其中變量類型是在編譯時靜態指定的)和動態語言(例如,Smalltalk和JavaScript,其中變量的類型可以在運行時改變)。靜態語言通常編譯成目標機器的本地機器代碼(或匯編代碼)程序,該程序在運行時直接由硬件執行。動態語言由解釋器執行,不產生機器語言代碼。

當然,事情后來變得復雜得多。虛擬機(VM)的概念開始流行,它其實只是一個高級的解釋器,用軟件模擬硬件設備。虛擬機使語言移植到新的硬件平臺更容易。因此,VM的輸入語言常常是中間語言。例如,一種編程語言(如Java)被編譯成中間語言(字節碼),然后在VM(JVM)中執行。

另外,現在有即時(JIT)編譯器。JIT編譯器在程序執行期間運行,即時編譯代碼。原先在程序創建期間(運行時之前)執行的編譯器現在稱為AOT編譯器。

一般來說,只有靜態語言才適合AOT編譯為本地機器代碼,因為機器語言通常需要知道數據的類型,而動態語言中的類型事先并不確定。因此,動態語言通常被解釋或JIT編譯。

在開發過程中AOT編譯,開發周期(從更改程序到能夠執行程序以查看更改結果的時間)總是很慢。但是AOT編譯產生的程序可以更可預測地執行,并且運行時不需要停下來分析和編譯。AOT編譯的程序也更快地開始執行(因為它們已經被編譯)。

相反,JIT編譯提供了更快的開發周期,但可能導致執行速度較慢或時快時慢。特別是,JIT編譯器啟動較慢,因為當程序開始運行時,JIT編譯器必須在代碼執行之前進行分析和編譯。研究表明,如果開始執行需要超過幾秒鐘,許多人將放棄應用。

以上就是背景知識。將AOT和JIT編譯的優點結合起來不是很棒嗎?請繼續閱讀。

編譯與執行Dart

在創造Dart之前,Dart團隊成員在高級編譯器和虛擬機上做了開創性的工作,包括動態語言(如JavaScript的V8引擎和Smalltalk的Strongtalk)以及靜態語言(如用于Java的Hotspot編譯器)。他們利用這些經驗使Dart在編譯和執行方面非常靈活。

Dart是同時非常適合AOT編譯和JIT編譯的少數語言之一(也許是唯一的“主流”語言)。支持這兩種編譯方式為Dart和(特別是)Flutter提供了顯著的優勢。

JIT編譯在開發過程中使用,編譯器速度特別快。然后,當一個應用程序準備發布時,它被AOT編譯。因此,借助先進的工具和編譯器,Dart具有兩全其美的優勢:極快的開發周期、快速的執行速度和極短啟動時間。

Dart在編譯和執行方面的靈活性并不止于此。例如,Dart可以編譯成JavaScript,所以瀏覽器可以執行。這允許在移動應用和網絡應用之間重復使用代碼。開發人員報告他們的移動和網絡應用程序之間的代碼重用率高達70%。通過將Dart編譯為本地代碼,或者編譯為JavaScript并將其與node.js一起使用,Dart也可以在服務器上使用。

最后,Dart還提供了一個獨立的虛擬機(本質上就像解釋器一樣),虛擬機使用Dart語言本身作為其中間語言。

Dart可以進行高效的AOT編譯或JIT編譯、解釋或轉譯成其他語言。Dart編譯和執行不僅非常靈活,而且速度特別快。

下一節將介紹Dart編譯速度的顛覆性的例子。

有狀態熱重載

Flutter最受歡迎的功能之一是其極速熱重載。在開發過程中,Flutter使用JIT編譯器,通常可以在一秒之內重新加載并繼續執行代碼。只要有可能,應用程序狀態在重新加載時保留下來,以便應用程序可以從停止的地方繼續。

除非自己親身體驗過,否則很難理解在開發過程中快速(且可靠)的熱重載的重要性。開發人員報告稱,它改變了他們創建應用的方式,將其描述為像將應用繪制成生活一樣。

以下是一位移動應用程序開發人員對Flutter熱重載的評價:

我想測試熱重載,所以我改變了顏色,保存修改,結果……就喜歡上它了!

這個功能真的很棒。我曾認為Visual Studio中編輯和繼續(Edit & Continue)很好用,但這簡直令人驚嘆。有了這個功能,我認為移動開發者的生產力可以提高兩倍。

這對我來說真的是翻天覆地的變化。當我部署代碼并花費很長時間時,我分心了,做了其他事情,當我回到模擬器/設備時,我就忘了想測試的內容。有什么比花5分鐘將控件移動2px更令人沮喪?有了Flutter,這不再存在。

Flutter的熱重載也使得嘗試新想法或嘗試替代方案變得更加容易,從而為創意提供了巨大的推動力。

到目前為止,我們討論了Dart給開發人員帶來的好處。下一節將介紹Dart如何使創建滿足用戶需求的順暢的應用程序更加輕松。

避免卡頓

應用程序速度快很不錯,但流暢則更加了不起。即使是一個超快的動畫,如果它不穩定,也會看起來很糟糕。但是,防止卡頓可能很困難,因為因素太多。Dart有許多功能可以避免許多常見的導致卡頓的因素。

當然,像任何語言一樣,Flutter也可能寫出來卡頓的應用程序;Dart通過提高可預測性,幫助開發人員更好地控制應用程序的流暢性,從而更輕松地提供最佳的用戶體驗。

效果怎樣呢?

以60fps運行,使用Flutter創建的用戶界面的性能遠遠優于使用其他跨平臺開發框架創建的用戶界面。

不僅僅比跨平臺的應用程序好,而且和最好的原生應用程序一樣好:

UI像黃油一樣順滑……我從來沒有見過這樣流暢的Android應用程序。

AOT編譯和“橋”

我們討論過一個有助于保持順暢的特性,那就是Dart能AOT編譯為本地機器碼。預編譯的AOT代碼比JIT更具可預測性,因為在運行時不需要暫停執行JIT分析或編譯。

然而,AOT編譯代碼還有一個更大的優勢,那就是避免了“JavaScript橋梁”。當動態語言(如JavaScript)需要與平臺上的本地代碼互操作時,它們必須通過橋進行通信,這會導致上下文切換,從而必須保存特別多的狀態(可能會存儲到輔助存儲)。這些上下文切換具有雙重打擊,因為它們不僅會減慢速度,還會導致嚴重的卡頓。


注意:即使編譯后的代碼也可能需要一個接口來與平臺代碼進行交互,并且這也可以稱為橋,但它通常比動態語言所需的橋快幾個數量級。另外,由于Dart允許將小部件等內容移至應用程序中,因此減少了橋接的需求。

搶占式調度、時間分片和共享資源

大多數支持多個并發執行線程的計算機語言(包括Java、Kotlin、Objective-C和Swift)都使用搶占式來切換線程。每個線程都被分配一個時間分片來執行,如果超過了分配的時間,線程將被上下文切換搶占。但是,如果在線程間共享的資源(如內存)正在更新時發生搶占,則會導致競態條件。

競態條件具有雙重不利,因為它可能會導致嚴重的錯誤,包括應用程序崩潰并導致數據丟失,而且由于它取決于獨立線程的時序,所以它特別難以找到并修復。在調試器中運行應用程序時,競態條件常常消失不見。

解決競態條件的典型方法是使用鎖來保護共享資源,阻止其他線程執行,但鎖本身可能導致卡頓,甚至更嚴重的問題(包括死鎖和饑餓)。

Dart采取了不同的方法來解決這個問題。Dart中的線程稱為isolate,不共享內存,從而避免了大多數鎖。isolate通過在通道上傳遞消息來通信,這與Erlang中的actor或JavaScript中的Web Worker相似。

Dart與JavaScript一樣,是單線程的,這意味著它根本不允許搶占。相反,線程顯式讓出(使用async/await、Future和Stream)CPU。這使開發人員能夠更好地控制執行。單線程有助于開發人員確保關鍵功能(包括動畫和轉場)完成而無需搶占。這通常不僅是用戶界面的一大優勢,而且還是客戶端——服務器代碼的一大優勢。

當然,如果開發人員忘記了讓出CPU的控制權,這可能會延遲其他代碼的執行。然而我們發現,忘記讓出CPU通常比忘記加鎖更容易找到和修復(因為競態條件很難找到)。

對象分配和垃圾回收

另一個嚴重導致卡頓的原因是垃圾回收。事實上,這只是訪問共享資源(內存)的一種特殊情況,在很多語言中都需要使用鎖。但在回收可用內存時,鎖會阻止整個應用程序運行。但是,Dart幾乎可以在沒有鎖的情況下執行垃圾回收。

Dart使用先進的分代垃圾回收和對象分配方案,該方案對于分配許多短暫的對象(對于Flutter這樣的反應式用戶界面來說非常完美,Flutter為每幀重建不可變視圖樹)都特別快速。Dart可以用一個指針凹凸分配一個對象(不需要鎖)。這也會帶來流暢的滾動和動畫效果,而不會出現卡頓。

統一的布局

Dart的另一個好處是,Flutter不會從程序中拆分出額外的模板或布局語言,如JSX或XML,也不需要單獨的可視布局工具。以下是一個簡單的Flutter視圖,用Dart編寫: 

new Center(child:
  new Column(children: [
    new Text('Hello, World!'),
    new Icon(Icons.star, color: Colors.green),
  ])
)


Dart編寫的視圖及其效果

注意,可視化這段代碼產生的效果是多么容易(即使你沒有使用Dart的經驗)。

Dart 2即將發布,這將變得更加簡單,因為newconst關鍵字變得可選,所以靜態布局看起來像是用聲明式布局語言編寫的: 

Center(child:
  Column(children: [
    Text('Hello, World!'),
    Icon(Icons.star, color: Colors.green),
  ])
)

然而,我知道你可能在想什么——缺乏專門的布局語言怎么會被稱為優勢呢?但它確實是顛覆性的。以下是一名開發人員在一篇題為“為什么原生應用程序開發人員應認真看待Flutter”的文章中寫的內容。

在Flutter里,界面布局直接通過Dart編碼來定義,不需要使用XML或模板語言,也不需要使用可視化設計器之類的工具。

說到這里,大家可能會一臉茫然,就像我當初的反應一樣。使用可視化工具不是更容易嗎?如果把所有的邏輯都寫到代碼里不是會讓事情變復雜嗎?

結果不然。天啊,它簡直讓我大開眼界。

首先是上面提到的熱重載。

這比Android的Instant Run和任何類似解決方案不知道要領先多少年。對于大型的應用同樣適用。如此快的速度,正是Dart的優勢所在。

實際上,可視化編輯器就變得多余了。我一點都不懷戀XCode的自動重布局。

Dart創建的布局簡潔且易于理解,而“超快”的熱重載可立即看到結果。這包括布局的非靜態部分。

結果,在Flutter中進行布局要比在Android/XCode中快得多。一旦你掌握了它(我花了幾個星期),由于很少發生上下文切換,因此會節省大量的開銷。不必切換到設計模式,選擇鼠標并開始點擊,然后想是否有些東西必須通過編程來完成,如何實現等等。因為一切都是程序化的。而且這些API設計得非常好。它很直觀,并且比自動布局XML更強大。

例如,下面是一個簡單的列表布局,在每個項目之間添加一個分隔線(水平線),以編程方式定義: 

return new ListView.builder(itemBuilder: (context, i) {
  if (i.isOdd) return new Divider(); 
  // rest of function
});

在Flutter中,無論是靜態布局還是編程布局,所有布局都存在于同一個位置。新的Dart工具,包括Flutter Inspector和大綱視圖(利用所有的布局定義都在代碼里)使復雜而美觀的布局更加容易。

Dart是專有語言嗎?

不,Dart(如Flutter)是完全開源的,具備清楚的許可證,同時也是ECMA標準的。Dart在Google內外很受歡迎。在谷歌內部,它是增長最快的語言之一,并被Adwords、Flutter、Fuchsia和其他產品使用;在谷歌外部,Dart代碼庫有超過100個外部提交者。

Dart開放性的更好指標是Google之外的社區的發展。例如,我們看到來自第三方的關于Dart(包括Flutter和AngularDart)的文章和視頻源源不斷,我在本文中引用了其中的一些內容。

除了Dart本身的外部提交者之外,公共Dart包倉庫中還有超過3000個包,其中包括Firebase、Redux、RxDart、國際化、加密、數據庫、路由、集合等方面的庫。

Dart程序員難找嗎?

如果沒有很多程序員知道Dart,找到合格的程序員會困難嗎?顯然不是。Dart是一門難以置信的易學語言。事實上,已經了解Java、JavaScript、Kotlin、C#或Swift等語言的程序員幾乎可以立即開始使用Dart進行編程。

一個程序員在名為“為什么Flutter 2018年將起飛”的文章中寫到:

Dart是用于開發Flutter應用程序的語言,很易學。谷歌在創建簡單、有文檔記錄的語言方面擁有豐富的經驗,如Go。到目前為止,對我來說,Dart讓我想起了Ruby,很高興能夠學習它。它不僅適用于移動開發,也適用于Web開發。

另一篇關于Flutter和Dart的文章,題為“為什么是Flutter而不是其他框架?”

Flutter使用由Google創建的Dart語言,老實說,我不喜歡C#或JAVA這樣的強類型語言,但我不知道Dart編寫代碼的方式有什么與眾不同。但我覺得寫起來很舒服。也許是因為它非常簡單易學,而且非常直觀。

Dart通過廣泛的用戶體驗研究和測試,專門設計得熟悉并易于學習。例如,在2017年上半年,Flutter團隊與八位開發人員一起進行了用戶體驗研究。我們給他們簡短地介紹了Flutter,然后給他們一個小時左右,創建了一個簡單的視圖。所有參與者都能夠立即開始編程,即使他們以前從未使用過Dart。他們專注于寫響應式視圖,而不是語言。Dart直接就能上手用了。

最后,一位參與者(在任務中進展得特別快)沒有提及任何有關該語言的內容,所以我們問他是否知道他正在使用哪種語言。他說不知道。語言不成問題;他在幾分鐘內就能用Dart編程。

學習新系統的難點通常不是學習語言,而是學習編寫好代碼的所有庫、框架、工具、模式和最佳實踐。Dart庫和工具格外出色,并且文檔詳盡。有一篇文章宣稱:“意外之喜是,他們還極其愛護代碼庫,并且他們擁有我見過的最好的文檔。”花費在學習Dart上的時間很容易通過學習其他東西節省的時間彌補。

作為直接證據,Google內部的一個大型項目希望將其移動應用程序移植到iOS。他們即將聘請一些iOS程序員,但轉而決定嘗試Flutter。他們監測了讓開發者上手Flutter需要多長時間。結果表明,程序員可以學會Dart和Flutter,并在三周內達到高效率。相比之下,他們之前觀察到僅僅讓程序員上手Android(更不用說他們必須聘用和培訓iOS開發人員)需要五個星期。

最后,一家將三種平臺(iOS、Android和Web)上的大型企業應用程序都遷移到Dart的公司,有一篇文章“我們為什么選擇Flutter以及它如何改變我們的公司”。他們的結論:

招人變得容易多了。無論他們是來自Web、iOS還是Android,我們現在都希望接受最佳人選。

現在我們擁有3倍的工作效率,因為我們所有的團隊都集中在一個代碼庫上。

知識共享達到前所未有的高度。

使用Dart和Flutter使他們的生產力提高到三倍。考慮到他們以前在做什么,這應該不會令人感到意外。與許多公司一樣,它們利用不同的語言、工具和程序員為每個平臺(Web、iOS和Android)構建獨立的應用程序。切換到Dart意味著他們不再需要雇傭三種不同的程序員。而且他們很容易將現有的程序員轉移到使用Dart。

他們和其他人發現,一旦程序員開始使用Flutter,他們就會愛上Dart。他們喜歡Dart的簡潔和缺乏儀式。他們喜歡級聯、命名參數、async/await和Stream等語言特性。而最重要的是,他們喜歡Dart帶來的Flutter功能(如熱重載),以及Dart幫助他們構建的美麗、高性能的應用程序。

Dart 2

在本文發表時,Dart 2正在發布。Dart 2專注于改善構建客戶端應用程序的體驗,包括加快開發人員速度、改進開發人員工具和類型安全。例如,Dart 2具有堅實的類型系統和類型推理。

Dart 2還使newconst關鍵字可選。這意味著可以在不使用任何關鍵字的情況下描述Flutter視圖,從而減少混亂并且易于閱讀。例如: 

Widget build(BuildContext context) =>
  Container(
    height: 56.0,
    padding: EdgeInsets.symmetric(horizontal: 8.0),
    decoration: BoxDecoration(color: Colors.blue[500]),
    child: Row(
      ...
    ),
  );

Dart 2自動計算出所有的構造函數,并且“padding:”的值是一個常量。

秘訣在于專注

Dart 2的改進集中在優化客戶端開發。但Dart仍然是構建服務器端、桌面、嵌入式系統和其他程序的絕佳語言。

專注是一件好事。幾乎所有持久受歡迎的語言都受益于非常專注。例如:

  • C是編寫操作系統和編譯器的系統編程語言。

  • Java是為嵌入式系統設計的語言。

  • JavaScript是網頁瀏覽器的腳本語言。

  • 即使是飽受非議的PHP也成功了,因為它專注于編寫個人主頁(它的名字來源)。

另一方面,許多語言已經明確地嘗試過(并且失敗了)成為完全是通用的,例如PL/1和Ada等等。最常見的問題是,如果沒有重點,這些語言就成了眾所周知的廚房洗碗槽。

許多使Dart成為好的客戶端語言的特性也使其成為更好的服務器端語言。例如,Dart避免了搶占式多任務處理,這一點與服務器上的Node具有相同的優點,但是數據類型更好更安全。

編寫用于嵌入式系統的軟件也是一樣的。Dart能夠可靠地處理多個并發輸入是關鍵。

最后,Dart在客戶端上的成功將不可避免地引起用戶對服務器上使用的更多興趣——就像JavaScript和Node一樣。為什么強迫人們使用兩種不同的語言來構建客戶端——服務器軟件呢?

結論

這對于Dart來說是一個激動人心的時刻。使用Dart的人喜歡它,而Dart 2中的新特性使其成為你工具庫中更有價值的補充。如果你還沒有使用過Dart,我希望這篇文章為你提供了有關Dart的新特性的有價值的信息,并且你會試一試Dart和Flutter。

干貨分享

敬請關注“PHP技術大全”微信公眾號


青海快三开奖信息