Flutter 事件機制 - Future 和 MicroTask 全解析
瞭解過Flutter的同學都知道,不同於 Android 原生開發,dart 是單執行緒實體的語言,所以我們一般的 非同步操作 ,實際上還是通過 單執行緒通過排程任務優先順序 來實現的,就是我們經常用到的 Future, 但是Flutter中的事件機制究竟是怎樣的?多個Future 和 Microtask 程式的執行順序是怎樣的? 本文將藉助兩個比較複雜的例子來詳細介紹 Flutter 的事件機制,希望能對大家有所幫助。
Main程式碼塊,EventQueue,MicrotaskQueue 的執行優先順序
首先我得提一嘴 isolate(隔離), isolate是有自己的記憶體和單執行緒控制的執行實體,isolate類似於執行緒。 執行中的 Flutter 程式由一個或多個 isolate 組成。我們的程式碼預設都在 Main isolate中執行。
為了保持高的響應性,特別耗時的任務一般不要放在Main isolate 中。但 isolate 不是本文的重點,在此就不過多贅述。
Dart 中事件機制的實現:Main isolate 中有一個Looper,但存在兩個Queue:Event Queue 和 Microtask Queue 。
因為 isolate 是單執行緒實體,所以 isolate中的程式碼是按順序執行的。
所以 dart 中的程式碼執行優先順序可以分為三個級別:
- 在 Main 中寫程式碼將最先執行;
- 執行完 Main 中的程式碼,然後會檢查並執行 Microtask Queue 中的任務, 通常使用 scheduleMicrotask 將事件新增到 MicroTask Queue 中;
- 最後執行 EventQueue 佇列中的程式碼,通常使用 Future 向 EventQueue加入時間,也可以使用 async 和 await 向 EventQueue 加入事件。
總結: Dart 中事件的執行順序:Main > MicroTask > EventQueue。
如圖:

驗證:
void testSX(){ new Future(() => print('s_1')); scheduleMicrotask(() => print('s_2')); print('s_3'); } 複製程式碼
輸出結果:
I/flutter (32415): s_3 I/flutter (32415): s_2 I/flutter (32415): s_1 複製程式碼
Future簡介
前面講到,用 async 和 await 組合,即可向 event queue 中插入 event 實現非同步操作,那為什麼還會有Future呢?
其實,Future 最主要的功能就是提供了鏈式呼叫。
new Future (() => print('拆分任務_1')) .then((i) => print('拆分任務_2')) .then((i) => print('拆分任務_3')) .whenComplete(()=>print('任務完成')); 複製程式碼
Future中的 then 並沒有建立新的Event丟到Event Queue中,而只是一個普通的Function,在一個 Future 所有的 Function 執行完後,下一個 Future 才會開始執行。
多個 Future 的執行順序
- 規則一 :Future 的執行順序為Future的在 EventQueue 的排列順序。類似於 JAVA 中的佇列,先來先執行。
- 規則二 :當任務需要延遲執行時,可以使用 new Future.delay() 來將任務延遲執行。
- 規則三 : Future 如果執行完才新增 than ,該任務會被放入 microTask,當前 Future 執行完會執行 microTask,microTask 為空後才會執行下一個Future。
- 規則四 :Future 是鏈式呼叫,意味著Future 的 then 未執行完,下一個then 不會執行。
理論結束,然後來看一段程式碼吧:
void testFuture() { Future f1 = new Future(() => print('f1')); Future f2 = new Future(() =>null); Future f3 = new Future.delayed(Duration(seconds: 1) ,() => print('f2')); Future f4 = new Future(() => null); Future f5 = new Future(() => null); f5.then((_) => print('f3')); f4.then((_) { print('f4'); new Future(() => print('f5')); f2.then((_) { print('f6'); }); }); f2.then((m) { print('f7'); }); print('f8'); } 複製程式碼
各位同學可以試著寫一下結果,然後對比下輸出結果。
輸出結果:
com.example.flutter_dart_app I/flutter: f8 com.example.flutter_dart_app I/flutter: f1 com.example.flutter_dart_app I/flutter: f7 com.example.flutter_dart_app I/flutter: f4 com.example.flutter_dart_app I/flutter: f6 com.example.flutter_dart_app I/flutter: f3 com.example.flutter_dart_app I/flutter: f5 com.example.flutter_dart_app I/flutter: f2 複製程式碼
是不是跟自己的結果大相徑庭,別急,看我來慢慢分析: 分析:
- 首先執行Main 的程式碼,所以首先輸出: 8;
- 然後參考上面的規則1, Future 1 到 5 是按初始化順序放入 EventQueue中,所以依次執行Future 1到5 , 所以輸出結果:8,1,7。
- 參考規則2, f3 延時執行 ,一定是在最後一個:8,1,7,…,2。
- 在 f4 中,首先輸出 f4 :8,1,7,4,…,2。
- 在 f4 的 then 的方法塊中,新建了Future, 所以新建的 Future 將在 EventQueue尾部 ,最後被執行:8,1,7,4,…,5,2。
- 在 f4 的 then 的方法塊中,給 f2 添加了 then ,但此時 f2 已經執行完了,參考規則三, 所以 then 中的程式碼會被放到 microTask 中,在當前 Future 執行完後執行。 因為此時Future f4已經執行完了,所以會處理microTask(microTask優先順序高)。結果:8,1,7,4,6,..,5,2。
- 此時我們的 EventQueue 中還有 f5,和在 f4 中新增的新的Future。 所以我們的最終結果就是:8,1,7,4,6,3,5,2。
是不是有點理解不了,沒事,牢記四個規則,自己再算一遍,相信你就瞭然於胸了。 重要要在腦海裡有一個 EventQueue 的佇列模型,牢記先進先出。
然後來試一試下一題:
多Future 和 多micTask 的執行順序
void testScheduleMicrotatsk() { scheduleMicrotask(() => print('Mission_1')); //註釋1 new Future.delayed(new Duration(seconds: 1), () => print('Mission_2')); //註釋2 new Future(() => print('Mission_3')).then((_) { print('Mission_4'); scheduleMicrotask(() => print('Mission_5')); }).then((_) => print('Mission_6')); //註釋3 new Future(() => print('Mission_7')) .then((_) => new Future(() => print('Mission_8'))) .then((_) => print('Mission_9')); //註釋4 new Future(() => print('Mission_10')); scheduleMicrotask(() => print('Mission_11')); print('Mission_12'); } 複製程式碼
大家可以先自己試一下,再對照結果~
輸出結果:
I/flutter (19025): Mission_12 I/flutter (19025): Mission_1 I/flutter (19025): Mission_11 I/flutter (19025): Mission_3 I/flutter (19025): Mission_4 I/flutter (19025): Mission_6 I/flutter (19025): Mission_5 I/flutter (19025): Mission_7 I/flutter (19025): Mission_10 I/flutter (19025): Mission_8 I/flutter (19025): Mission_9 Syncing files to device MIX 3... I/flutter (19025): Mission_2 複製程式碼
是不是還是沒答全對?沒關係,很正常,看我慢慢道來:
分析:
- 根據 Main > MicroTask > EventQueue。我們首先會得到輸出結果:12,1,11。
- 註釋1 的 Future 是延時執行,所以:12,1,11,…,2。
- 註釋2 中建立了 Microtask,Microtask會在該Future執行完後執行 ,所以:12,1,11,4,6,5,…,2。
- 重點來了。我們在註釋3 的Future 的 then 中新建了Future(輸出Mission_8), 新建的 Future 將被加到 EventQueue尾部 ,並且, 註釋3的Future後續的then將不再執行,因為這個鏈被阻塞了!
注意對比上一題中的 f4, 上一題中的 f4 是一個 than 方法包裹了程式碼塊。
此時的結果:12,1,11,4,6,5,7,…,2。 - 執行完註釋4 的 Future,然後會執行我們在註釋3 Future 新加入的 Future,之後註釋3 的Future不再阻塞,會繼續執行,結果: 12,1,11,4,6,5,7,10,8,9,2。
看到這裡,相信各位同學已經對 Dart 事件機制有一個大概的瞭解,希望能對 各位在學Flutter 的同學有所幫助,蟹蟹~
END
我是雷加,如果您喜歡我的文章,請留下你的贊;如有疑問和建議,請在評論區留言
我的 Github , 歡迎關注~