Flutter 事件機制 - Future 和 MicroTask 全解析

寫在前面

瞭解過Flutter的同窗都知道,不一樣於 Android 原生開發,dart 是單線程實體的語言,因此咱們通常的異步操做,實際上仍是經過單線程經過調度任務優先級來實現的,就是咱們常常用到的 Future,可是Flutter中的事件機制到底是怎樣的?多個Future 和 Microtask 程序的執行順序是怎樣的? 本文將藉助兩個比較複雜的例子來詳細介紹 Flutter 的事件機制,但願能對你們有所幫助。git

Main代碼塊,EventQueue,MicrotaskQueue 的執行優先級

首先我得提一嘴 isolate(隔離),isolate是有本身的內存和單線程控制的運行實體,isolate相似於線程。 運行中的 Flutter 程序由一個或多個 isolate 組成。咱們的代碼默認都在 Main isolate中執行。
爲了保持高的響應性,特別耗時的任務通常不要放在Main isolate 中。但 isolate 不是本文的重點,在此就不過多贅述。github

Dart 中事件機制的實現 :Main isolate 中有一個Looper,但存在兩個Queue:Event Queue 和 Microtask Queue 。
由於 isolate 是單線程實體,因此 isolate中的代碼是按順序執行的。
因此 dart 中的代碼執行優先級能夠分爲三個級別:
bash

  1. 在 Main 中寫代碼將最早執行;
  2. 執行完 Main 中的代碼,而後會檢查並執行 Microtask Queue 中的任務, 一般使用 scheduleMicrotask 將事件添加到 MicroTask Queue 中;
  3. 最後執行 EventQueue 隊列中的代碼,一般使用 Future 向 EventQueue加入時間,也可使用 async 和 await 向 EventQueue 加入事件。

總結:Dart 中事件的執行順序:Main > MicroTask > EventQueue。
如圖:app

驗證:

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 最主要的功能就是提供了鏈式調用。async

new Future (() => print('拆分任務_1'))
    .then((i) => print('拆分任務_2'))
    .then((i) => print('拆分任務_3'))
    .whenComplete(()=>print('任務完成'));
複製代碼

Future中的 then 並無建立新的Event丟到Event Queue中,而只是一個普通的Function,在一個 Future 全部的 Function 執行完後,下一個 Future 纔會開始執行。oop

多個 Future 的執行順序

  1. 規則一:Future 的執行順序爲Future的在 EventQueue 的排列順序。相似於 JAVA 中的隊列,先來先執行。
  2. 規則二:當任務須要延遲執行時,可使用 new Future.delay() 來將任務延遲執行。
  3. 規則三: Future 若是執行完才添加 than ,該任務會被放入 microTask,當前 Future 執行完會執行 microTask,microTask 爲空後纔會執行下一個Future。
  4. 規則四:Future 是鏈式調用,意味着Future 的 then 未執行完,下一個then 不會執行。

理論結束,而後來看一段代碼吧:ui

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');
}
複製代碼

各位同窗能夠試着寫一下結果,而後對比下輸出結果。spa

輸出結果:線程

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
複製代碼

是否是跟本身的結果截然不同,別急,看我來慢慢分析: 分析:

  1. 首先執行Main 的代碼,因此首先輸出: 8;
  2. 而後參考上面的規則1,Future 1 到 5 是按初始化順序放入 EventQueue中,因此依次執行Future 1到5 , 因此輸出結果:8,1,7。
  3. 參考規則2,f3 延時執行,必定是在最後一個:8,1,7,…,2。
  4. 在 f4 中,首先輸出 f4 :8,1,7,4,…,2。
  5. 在 f4 的 then 的方法塊中,新建了Future, 因此新建的 Future 將在 EventQueue尾部,最後被執行:8,1,7,4,…,5,2。
  6. 在 f4 的 then 的方法塊中,給 f2 添加了 then ,但此時 f2 已經執行完了,參考規則三,因此 then 中的代碼會被放到 microTask 中,在當前 Future 執行完後執行。 由於此時Future f4已經執行完了,因此會處理microTask(microTask優先級高)。結果:8,1,7,4,6,..,5,2。
  7. 此時咱們的 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
複製代碼

是否是仍是沒答全對?不要緊,很正常,看我慢慢道來:
分析:

  1. 根據 Main > MicroTask > EventQueue。咱們首先會獲得輸出結果:12,1,11。
  2. 註釋1 的 Future 是延時執行,因此:12,1,11,…,2。
  3. 註釋2 中建立了 Microtask,Microtask會在該Future執行完後執行,因此:12,1,11,4,6,5,…,2。
  4. 重點來了。咱們在註釋3 的Future 的 then 中新建了Future(輸出Mission_8),新建的 Future 將被加到 EventQueue尾部,而且,註釋3的Future後續的then將再也不執行,由於這個鏈被阻塞了!
    注意對比上一題中的 f4, 上一題中的 f4 是一個 than 方法包裹了代碼塊。
    此時的結果:12,1,11,4,6,5,7,…,2。
  5. 執行完註釋4 的 Future,而後會執行咱們在註釋3 Future 新加入的 Future,以後註釋3 的Future再也不阻塞,會繼續執行,結果: 12,1,11,4,6,5,7,10,8,9,2。

看到這裏,相信各位同窗已經對 Dart 事件機制有一個大概的瞭解,但願能對 各位在學Flutter 的同窗有所幫助,蟹蟹~

END

我是雷加,若是您喜歡個人文章,請留下你的贊;若有疑問和建議,請在評論區留言
個人 Github, 歡迎關注~

相關文章
相關標籤/搜索