天天看點

Dart語言概覽

前面對Dart語言的基本文法做了簡單介紹,本篇文章我們站在一個更高的次元來聊一聊Dart。

在學習一門新技術的時候,千萬不要陷入細節裡。我們學習一門語言,并不是為了成為語言專家,而是為了解決實際問題。通過幾天的學習,在了解了一門語言是如何表達資訊和處理資訊之後,去實踐,去邊做邊學就OK了。

Dart是什麼?

2011年10月,在丹麥召開的GOTO大會上,Google釋出了一種新的程式設計語言——Dart。如同Kotlin和Swift的出現,分别是為了解決Java和Objective-C在編寫應用程式的一些實際問題一樣,Dart的誕生正是要解決JavaScript存在的、在其語言本質上無法改進的缺陷。

JavaScript之父 布蘭登 艾克(Brendan Eich)曾在一次采訪中說:JavaScript幾天就設計出來了。由于設計時間太短,很多細節考慮不完善,導緻後來很長一段時間,使用JavaScript開發的程式混亂不堪。出于對JavaScript的不滿,Google程式員們決定自己寫一個新的語言來換掉它,是以Dart的最初定位也是一種運作在浏覽器中的腳本語言。

而為了推廣Dart,Google甚至将自己的Chrome浏覽器内置了Dart VM,可以直接高效地運作Dart代碼。而對于普通浏覽器來說,Google也提供了一套能夠将Dart代碼編譯成JavaScript的轉換工具。這樣一來,開發者們就可以毫無顧慮地去使用Dart進行開發了,而不必擔心相容問題。再加上出身名門,Dart在一開始就赢得了部分前端開發者的關注。

但是,JavaScript的生命力似乎比預想的更強大。

原本JavaScript隻能在浏覽器中運作,但是Node.js的出現讓它開始有能力運作在服務端,很快手機應用與桌面應用也成為了JavaScript的宿主容器,一些明星項目比如React、React Native、Vue等架構如雨後春筍般崛起,迅速擴充了它的邊界。

于是,JavaScript成為了前後端通吃的全棧語言。就如同Atwood定律描述的:凡是能用JavaScript寫出來的系統,最終都會用JavaScript寫出來。

JavaScript因為Node.js煥發了第二春,而Dart就沒有這麼好的運氣了。由于缺少頂級項目的使用,Dart始終不溫不火。2015年,在聽取了大量開發者的回報之後,Google決定将内置的Dart VM引擎從Chrome中移除,這對Dart發展來說是重大挫折,代理JavaScript就更無從談起了。

但,Dart也借此機會開始轉型:在Google内部孵化了移動開發架構Flutter,彎道超車進入移動開發的領域;而在Google未來的作業系統Fuchsia中,Dart更是被指定為官方的開發語言。

Dart的特性

作為移動端開發的後來者,Dart語言可以說是集百家之長,擁有其他優秀程式設計語言的諸多特性和影子,是以對于其他語言的開發者而言,學習成本無疑是非常低的。接下來我和你分享一下它的核心特性。

JIT與AOT

借助于先進的工具鍊和編譯器,Dart是少數同時支援JIT(Just In Time,即時編譯)和AOT(Ahead Of Time,運作前編譯)的語言之一。那麼什麼是JIT和AOT呢?

語言在運作之前通常都需要編譯,JIT和AOT則是最常見的兩種編譯模式。

  • JIT在運作時即時編譯,可以動态下發和執行代碼,開發測試效率高,但是運作速度和執行性能會因為運作時即時編譯受到影響。
  • AOT即提前編譯,可以生成被直接執行的二進制代碼,運作速度快,執行性能高,但是每次執行前都需要重新編譯,開發測試效率低。

總結來講,在開發期使用JIT編譯,可以提高開發測試效率、縮短産品的開發周期。Flutter最受歡迎的功能之一熱重載,正是基于此特性。而在釋出期使用AOT,就不需要像React Native那樣在跨平台JavaScript代碼和原生Android、iOS代碼之間建立低效的方法調用映射關系。是以,Dart相對JS具有運作速度快、執行性能好的特點。

那麼,如何區分一門語言究竟是JIT還是AOT呢?通常而言,看代碼在執行前是否需要編譯即可。如果需要,一般屬于AOT;如果不需要,屬于JIT。

AOT的代表是C/C++,其代碼在執行前都必須編譯成機器碼;JIT則包含了JavaScript、Python等幾乎所有的腳本語言。

記憶體配置設定與垃圾回收

Dart VM的記憶體配置設定政策比較簡單,建立對象時隻需要在堆上移動指針,記憶體增長始終是線性的,省去了查找可用記憶體的過程。

在Dart中,并發是通過Isolate實作的。Isolate是類似于線程,但是不共享記憶體、獨立運作的worker。這樣的機制,就可以讓Dart實作無鎖的快速配置設定。

Dart的垃圾回收,則是采用了多生代算法。新生代在回收記憶體時采用“半空間”機制,觸發垃圾回收時,Dart會将目前“半空間”中的“活躍”對象拷貝至備用空間,然後整體釋放目前空間的所有内容。回收過程中,Dart隻需要操作少量的“活躍”對象,沒有引用的大量“死亡對象”則被忽略,這樣的回收機制很适合Flutter架構中大量Widget銷毀重建的場景。

單線程模型

支援并發執行線程的進階語言(比如,C++、Java、Objective-C),大都以搶占式的方式切換線程,即:每個線程都會被配置設定一個固定的時間片來執行,超過了時間片之後線程上下文将被搶占後切換。如果這時正在更新線程間的共享資源,搶占後就可能導緻資料不同步的問題。

解決這一問題的典型方法是,使用鎖來保護共享資源,但是鎖本身又可能會帶來性能損耗等更嚴重的問題。

這時,Dart是單線程模型的優勢就展現出來了,因為它天然不存在資源競争和狀态同步的問題。這就意味着,一旦某個函數開始執行,就将執行到這個函數結束,而不會被其他Dart代碼打斷。

是以,Dart中并沒有線程,隻有Isolate(隔離區)。Isolate之間不會共享記憶體,就像幾個運作在不同程序中的Worker,通過事件循環(Event Looper)在事件隊列(Event Queue)上傳遞消息通信。

無需單獨的聲明式布局語言

在Flutter中,界面布局直接通過Dart編碼來定義。

Dart聲明式程式設計布局易于閱讀和可視化,使得flutter并不需要類似JSX或XML的聲明式布局語言。所有的布局都使用同一種格式也使得Flutter很容易提供進階工具使布局更簡單。

開發過程中也不需要可視化界面建構器,因為熱重載可以讓我們立即在手機上看到運作效果。

Dart的未來

一種程式設計語言,并不是說搞定了引擎和開發者接口就完成了,而是必須在這個語言得以立足的庫、架構、應用程式等“生态”都成熟起來之後,其價值才會真正展現。而要走到這一步,通常需要花上數年時間。

目前,基于Dart語言的第三方庫還很少,并且品質一般。不過值得慶幸的是,由于Flutter和Fuchsia的推送,Dart SDK更新疊代的速度快了很多,開發者的熱情也急劇增長,Dart的生态增速很快。

我覺得,Dart是否能夠成功,目前來看主要取決于Flutter和Fuchsia是否能夠成功。而Flutter是建構Fuchsia的UI開發架構,是以這個問題也就變成了Fuchsia是否能夠成功。

截止2019年7月9号,Flutter正式版釋出也就半年多的時間,目前在GitHub上的star數是69.5K,而React Native 是78.8K,可見Flutter的熱度之高。

Google在遭受與Oracle的Java侵權案後,痛定思痛下決心要發展自己的語言生态系統:Dart憑借Flutter和Fuchsia的生态主攻前端和移動端,而服務端,則有借助于Docker的火熱勢頭增長迅猛的Go語言。

是以說,Google的布局不僅全面,應用和影響也非常廣泛,前後端均有殺手級作品用來建構語言生态。相信随着Google新系統Fuchsia的釋出,Flutter和Dart會以更迅猛的速度釋放他們的力量,而Google統一前後端開發技能棧的願望也在一定程度上得以實作。

總結

Dart是一門現代語言,集合了各種語言的優秀特點。如果你不了解Dart也無需擔心,隻要你有過其他程式設計語言,尤其是Java、或者Objective-C程式設計經驗的話,可以很容易的在dart身上找到他們的影子,以極低的成本快速上手。