Dart
是一個單執行緒的語言,它提供了future
、stream
、background wotk
、和其他的事件、非同步,對於Flutter而言,本章節講解了Dart的後臺工作基礎:隔離和事件迴圈。
Isolates
所有Dart程式碼都在其中執行隔離程式。它就像是機器上的一個小空間,具有自己的私有記憶體塊和一個執行事件迴圈的單個執行緒。
在許多其他語言(例如C ++
)中,您可以讓多個執行緒共享相同的記憶體並執行所需的任何程式碼。但是,在Dart
中,每個執行緒都處於其自己的隔離區中,並擁有自己的記憶體,並且該執行緒僅處理事件(一分鐘內會處理更多事件)。
許多Dart
應用程式都在單個隔離中執行所有程式碼,但是如果需要,您可以擁有多個。如果要執行的計算量如此之大,以至於如果它在主隔離中執行,可能會導致丟幀,那麼可以使用Isolate.spawn()
或Flutter
的compute()
函式。這兩個函式都建立了一個單獨的隔離程式來處理數字,使您的主要隔離程式可以自由地(例如)重建和渲染小部件樹。
新隔離區擁有自己的事件迴圈和記憶體,即使原始隔離區是該新隔離區的父級,也不允許其訪問。這就是孤立的名稱:這些小空間彼此隔離。
實際上,隔離器可以一起工作的唯一方法是通過來回傳遞訊息。一個隔離向另一個傳送訊息,接收隔離使用其事件迴圈處理該訊息。
缺少共享記憶體聽起來可能很嚴格,尤其是如果您使用的是Java
或C ++
之類的語言時,但這對Dart
編碼人員來說有一些關鍵的好處。
例如,隔離中的記憶體分配和垃圾回收不需要鎖定。只有一個執行緒,因此,如果不很忙,您就知道記憶體沒有被更改。這對於Flutter
應用程式來說效果很好,有時需要快速構建和拆除一堆小部件。
Event loops
現在,您已經對隔離有了基本的介紹,讓我們深入研究真正使非同步程式碼成為可能的事情:事件迴圈
。
想象一下,應用程式的生命週期在時間軸上延伸。該應用程式啟動,該應用程式停止,並且在一系列事件之間發生–來自磁碟的I/O
,來自使用者的手指敲擊……各種各樣的東西。
您的應用無法預測這些事件何時發生或以什麼順序發生,因此必須使用一個永不阻塞的執行緒來處理所有這些事件。因此,該應用執行一個事件迴圈。它從事件佇列中獲取最舊的事件,進行處理,返回到下一個事件,然後進行處理,依此類推,直到事件佇列為空。
應用程式在整個執行過程中-您在螢幕上點選,下載內容,計時器關閉-該事件迴圈不斷迴圈,一次處理一次這些事件。
當操作中斷時,執行緒只會掛出,等待下一個事件。它可以觸發垃圾收集器,獲取咖啡,等等。
Dart
用於非同步程式設計的所有高階API
和語言功能(期貨,流,非同步和等待)都基於此簡單迴圈而構建。
例如,假設您有一個啟動網路請求的按鈕,如下所示:
RaisedButton(
child: Text('Click me'),
onPressed: () {
final myFuture = http.get('https://example.com');
myFuture.then((response) {
if (response.statusCode == 200) {
print('Success!');
}
});
},
)
複製程式碼
當你啟動你的APP
,Flutter
編譯這個button
,然後渲染它,然後APP就開始等待事件。
您應用的事件迴圈只是閒著,等待下一個事件。與按鈕無關的事件可能會進入並得到處理,而按鈕坐在那裡等待使用者點選它。最終他們做到了,而點選事件進入了佇列。
該事件將被處理。 Flutter
看著它,並且渲染系統說:“那些座標與凸起的按鈕匹配,”因此Flutter
執行onPressed
函式。該程式碼啟動一個網路請求(返回一個將來的請求),並使用then()
方法註冊一個將來的完成處理程式。
而已。迴圈完成了該點選事件的處理,並且已將其丟棄。
現在,onPressed
是RaisedButton
的一個屬性,並且網路事件將回撥用於將來,但是這兩種技術都在做相同的基本操作。它們都是告訴Flutter
的一種方式,“嘿,稍後,您可能會看到一種特定型別的事件。當您這樣做時,請執行這段程式碼。”
因此,onPressed
正在等待點選,而未來正在等待網路資料,但是從Dart
的角度來看,這些都只是佇列中的事件。
這就是Dart
中非同步編碼的工作方式。期貨,資料流,非同步和等待-這些API
只是告訴您的方式 Dart
的事件迴圈,“這裡有一些程式碼,請稍後執行。”
如果我們回顧一下該程式碼示例,您現在可以確切地看到它如何分解為特定事件的塊。 有初始版本(1),點選事件(2)和網路響應事件(3)。
RaisedButton( // (1)
child: Text('Click me'),
onPressed: () { // (2)
final myFuture = http.get('https://example.com');
myFuture.then((response) { // (3)
if (response.statusCode == 200) {
print('Success!');
}
});
},
)
複製程式碼
習慣了使用非同步程式碼後,您將開始在各處識別這些模式。在繼續使用更高階別的API
時,瞭解事件迴圈將有所幫助.
我們快速瞭解了Dart
中的隔離,事件迴圈和非同步編碼的基礎。如果您要查詢更多詳細資訊,例如微任務佇列的工作方式,請參閱過時的,但仍備受喜愛的文章事件迴圈和Dart
。
翻譯 fgyong
日期 2020.7.28