學習 Dart 的異步編程時,須要對異步編程所涉及的相關知識體系進行梳理,咱們可根據如下幾個發問來逐個瞭解異步編程涉及的內容:數組
Dart是單「線程」語言:異步
Dart 代碼在某個 isolate 的上下文中運行,該 isolate 擁有 Dart 代碼所需的全部內存。當Dart 代碼正在執行時,同一個 isolate 中的其餘代碼都沒法運行,更通俗地講,Dart 一次執行一個操做,這意味着只要一個操做正在執行,它就不會被任何其餘 Dart 代碼中斷。這就引起出如下問題:async
1,若是 Dart 代碼正在執行長耗時計算,或者等待 I/O,將會致使程序凍結;ide
2,若是須要同時運行不一樣的 Dart 代碼,就須要將這些代碼放在不一樣的 isolate 環境中執行 ;異步編程
3, 如何在 Dart 中編寫異步代碼,進行異步操做?(所謂異步操做,指的是當你的程序在等待其它操做完成時,可讓其先完成其它部分的操做)oop
咱們先放碼出來:學習
main() { fallInLove();//談戀愛 House newHourse = buyHouse();//買房(耗時、費力操做) livingHouse(newHourse);//買完房子以後住進新房 marry();//結婚 haveChild();//生娃 }
如上所示,在這種狀況下,只有當第一條語句執行完以後,後面的語句才能接着按順序執行;ui
大部分人的人生三件事:買房,結婚,生娃!線程
這三件大事,若是用 Dart 語言來實現:
若是是在同步操做中,而且家裏沒礦,六個錢包也湊不齊首付的話,你的人生就會凍結- -等着買完房以後,才能結婚,結完婚以後才能生娃;
有沒有什麼操做能夠實現先結婚,再生娃,再買房呢?答案是有的:若是將買房(buyHouse())放在異步操做裏,這時候你要給你的丈母孃及老婆一個承諾:之後有錢了再買房!如今先結婚、生娃!詳情咱們後文再敘,這裏先提出這麼個設想;
當開始運行 Flutter 或者 Dart 應用程序時,一個 isolate 就會被建立並啓動,當 isolate 建立成功時,Dart 就會進行以下三個事項:
1,初始化兩個先進先出(FIFO)隊列:一個稱爲 MicroTask 隊列,另一個稱爲 Event 隊列;
2,執行main()方法,且執行完成後,進入3
3,啓動 Event Loop
4,開始處理兩個隊列中的元素(兩個隊列的執行有前後順序,見後文)
也就是說,每一個 isolate 中都會有且只有一個Event Loop(事件循環)和兩個隊列(MicroTask Queue、Event Queue ); Event Loop 將根據MicroTask隊列和Event隊列裏的內容來驅動代碼的執行方式和順序。
那麼問題來了:
1,Event Loop是什麼?用來幹啥的?
2,MicroTask隊列和Event隊列都分別是什麼?有什麼用?
3,二者有什麼區別?
Event Loop是一個按期喚醒的無限循環:它在MicroTask、Event隊列中查找是否有須要運行的任務。若是隊列中的任務存在,則當且僅當CPU空閒時,Event Loop將它們放入運行堆棧執行。
MicroTask Queue用於很是短的,須要異步運行的操做,考慮以下場景:想要在稍後完成一些任務但又但願是在執行下一個Event隊列以前;通常使用dart:async庫中的scheduleMicrotask方法來實現;
Event Queue(事件隊列)包含全部外部事件:
每次外部事件被觸發時,要執行的相應代碼都會被添加到 Event Queue 中,當MicroTask隊列中沒有任何內容時,Event Loop纔會從Event 隊列中取出第一項來處理;須要重點關注的是,Future也會被添加到 Event 隊列中;
當main()方法執行完成後,event loop開始它的工做,
1,先從 microtask 隊列以先進先出的方式取出並執行完全部內容;
2,從event 隊列中取出並處理第一項;
3,重複上述兩個步驟直到兩個隊列都沒有任何內容可執行
綜上所述,能夠由以下簡化圖來表示:
Future 一般指的是異步運行的任務,它會在將來某個時間點完成,這裏的完成有兩層含義:成功或者失敗,成功時返回任務執行的結果(注意:這裏的結果指的是 Future< T> 返回範型T的對象),失敗時返回錯誤;
當實例化一個 Future 的時候:
import 'dart:async'; void main() { fallInLove(); //談戀愛; handleHouse(); //買房、入住(耗時、費用的操做) marry(); //結婚 haveChild(); //生娃 } ///進行買房 [buyHouse]、入住[livingHouse]等操做 void handleHouse() { Future<House> house = buyHouse(); house.then((_) { livingHouse(); }); } class House {} Future<House> buyHouse() { Future<House> result = Future(() { print('buyHouse'); }); return result; } void livingHouse() { print('livingHouse'); } void marry() { print('marry'); } void haveChild() { print('haveChild'); } void fallInLove() { print('fall in love'); }
咱們來分析上述代碼的執行順序:
main()
方法中開始執行同步代碼,首先執行fallInLove()
;handleHouse()
方法,將Future裏的(){print('buyHouse');}
加入 Event 隊列;marry()
方法;haveChild()
方法;main()
方法已經執行完了,Event Loop開始處理兩個隊列中的元素,如前面的分析,這時候先查看MicroTask隊列有沒有須要處理的任務,沒有的話,就能夠取出Event隊列中的第一個任務來執行,在這個例子中,就是開始執行步驟2的(){print('buyHouse');}
代碼塊;then()
中的方法 livingHouse()
;;因此代碼的執行結果應該以下所示:
fall in love
marry
haveChild
buyHouse
livingHouse
上面的 Future 章節,咱們主要使用了 Future 的 API 來達到異步操做的目的,Dart 還爲咱們提供了一對關鍵字 async/await 來達成此目的;有了這兩個關鍵字,咱們能夠像寫同步代碼那樣寫異步代碼,而且不用使用到 Future的 API (then());
使用 async/await 關鍵字有如下幾個須要注意的點:
以下:咱們只須要稍微改造handleHouse()
方法:
handleHouse()
方法的返回類型改成 Future< void>///進行買房 [buyHouse]、入住[livingHouse]等操做 Future<void> handleHouse() async { await buyHouse(); livingHouse(); }
運行代碼後的輸出效果是與使用Future API 一致的;
本文主要涉及到的概念有:isolate,event loop,future,async/await,理解了這些內容,可讓咱們更好地寫出、閱讀異步編程的相關代碼;
參考連接1:https://dart.dev/tutorials/language/futures
參考連接2:https://dart.dev/guides/language/language-tour#asynchrony-support
參考連接3:https://dart.dev/articles/archive/event-loop#event-queue-new-future