天天看點

Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)

      小菜嘗試過 Future 和 Stream 實作 Dart 異步處理,但僅限于基本的使用,網上有很多相關的資料,小菜僅從初識者的角度學習了解 Dart 的實作的異步處理;

      Dart 是單線程的!這點很重要,是不可變更的;但單線程的 Dart 是如何實作多線程的,這是很值得研究的;

      小菜了解的異步操作來處理耗時任務的方式主要是兩種:一種是類似于 Java 的開啟多線程,并線上程間通信;另一種是類似于 Dart 的單線程和事件循環 Event Loop;其中 Event Loop 事件循環就是把一系列的(點選事件/滑動事件/網絡請求/ IO 事件等)事件存放在 Event Queue 隊列中,循環執行從 Event Loop 中擷取事件進行執行,直到清空隊列事件;

Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
      Dart 可以通過 Future 和 Stream 實作異步操作,小菜先盡量全面的學習 Future;

Future

Future Methods

      Future 的應用主要涉及三種狀态,分别是未完成狀态(UnCompleted / Pending),完成成功(Completed with Data),完成失敗(Completed with Error);

Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)

      當 Future 任務執行完成之後,通常需要一個回調,這個回調會立即執行,不會添加到事件隊列中,其中通過 then() 的成功回調來來監聽 Future 執行完成時擷取到的結果;通過 catchError() 異常回調來監聽 Future 執行失敗或者出現異常時的錯誤資訊;通過 whenComplete() 最終回調來擷取最終回調,不管成功還是失敗;

      小菜做了一個不太嚴謹的對比,這三種狀态類似于 try-catch-finally,其中 try 對應 then() 成功回調,catch 對應 catchError() 異常回調,而 finally 對應 whenComplete() 最終回調;

Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)

      Future 還有兩個常用的回調,分别是 timeout 逾時回調和 asStream() 轉換成 Stream 流回調;

Future 的使用可以通過 Future Constructors 構造方法或 async-await 方式;

Future.delayed(Duration(seconds: 3), () {
  print('Future.delayed(), CurrentTime = ${DateTime.now().millisecondsSinceEpoch}');
  return 'Future.delayed() result! CurrentTime = ${DateTime.now().millisecondsSinceEpoch}';
}).timeout(Duration(seconds: 1), onTimeout: () => 'Future.delayed() TimeOut! CurrentTime = ${DateTime.now().millisecondsSinceEpoch}')
    .then((val) => print(val))
    .whenComplete(() => print('Future.delayed() whenComplete! CurrentTime = ${DateTime.now().millisecondsSinceEpoch}'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)

Future Constructors

1. Future(FutureOr computation())

      用于傳回狀态結果的基本構造方法;其中 computation 傳回的可以是普通類型也可以是 Future;

factory Future(FutureOr<T> computation()) {
    _Future<T> result = new _Future<T>();
    Timer.run(() {
      try {
        result._complete(computation());
      } catch (e, s) {
        _completeWithErrorCallback(result, e, s);
      }
    });
    return result;
}           

      分析源碼可知,Future 主要是通過 Timer.run() 來執行,在回調方法中執行 computation();

Future(() => print('Future(FutureOr<T> computation()) 01'));
Future(() {
  print('Future(FutureOr<T> computation()) 02');
  return 'Future(FutureOr<T> computation()) 02 result!';
}).then((val) => print(val));
Future(() {
  print('Future(FutureOr<T> computation()) 03');
  return 'Future(FutureOr<T> computation()) 03 result!';
}).then((val) => print(val)).whenComplete(() => print('Future(FutureOr<T> computation()) 03 whenComplete!'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
2. Future.value([FutureOr value])

      建立一個固定類型的 Future;

Future.value('Future.value() 01').then((val) => print(val));
Future.value('Future.value() 02').then((val) => print(val));
Future.value('Future.value() 03')
    .then((val) => print(val))
    .whenComplete(() => print('Future.value() 03 whenComplete!'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
3. Future.delayed(Duration duration, [FutureOr computation()])

      delayed 是延遲執行,任務會到設定的延遲時間之後再執行;

factory Future.delayed(Duration duration, [FutureOr<T> computation()]) {
    _Future<T> result = new _Future<T>();
    new Timer(duration, () {
      if (computation == null) {
        result._complete(null);
      } else {
        try {
          result._complete(computation());
        } catch (e, s) {
          _completeWithErrorCallback(result, e, s);
        }
      }
    });
    return result;
}           

      分析源碼可知,與預設的構造方法相比,Timer 隻是多了一個 duration,會在 duration 之後調用 computation();

print('CurrentTime01 = ${DateTime.now().millisecondsSinceEpoch}');
Future.delayed(Duration(seconds: 3), () => print('Future.delayed() 01, CurrentTime = ${DateTime.now().millisecondsSinceEpoch}'));
print('CurrentTime02 = ${DateTime.now().millisecondsSinceEpoch}');
Future.delayed(Duration(seconds: 1), () => print('Future.delayed() 02, CurrentTime = ${DateTime.now().millisecondsSinceEpoch}'));
print('CurrentTime03 = ${DateTime.now().millisecondsSinceEpoch}');
Future.delayed(Duration(seconds: 2), () {
  print('Future.delayed() 03, CurrentTime = ${DateTime.now().millisecondsSinceEpoch}');
  return 'Future.delayed() 03 result! CurrentTime = ${DateTime.now().millisecondsSinceEpoch}';
}).then((val) => print(val)).whenComplete(() => print('Future.delayed() 03 whenComplete! CurrentTime = ${DateTime.now().millisecondsSinceEpoch}'));
print('CurrentTime04 = ${DateTime.now().millisecondsSinceEpoch}');           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
4. Future.sync(FutureOr computation())

      sync 是同步方法,任務會被立即執行;

factory Future.sync(FutureOr<T> computation()) {
    try {
      var result = computation();
      if (result is Future<T>) {
        return result;
      } else {
        return new _Future<T>.value(result);
      }
    } catch (error, stackTrace) {
      var future = new _Future<T>();
      AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
      if (replacement != null) {
        future._asyncCompleteError(
            _nonNullError(replacement.error), replacement.stackTrace);
      } else {
        future._asyncCompleteError(error, stackTrace);
      }
      return future;
    }
}           

      分析源碼可知,與預設的構造方法相比,sync 直接調用 computation(),并未通過 Timer() 的回調;

Future.sync(() => print('Future.sync() 01'));
Future.sync(() {
  print('Future.sync() 02');
  return 'Future.sync() 02 result!';
}).then((val) => print(val));
Future.sync(() {
  print('Future.sync() 03');
  return 'Future.sync() 03 result!';
}).then((val) => print(val)).whenComplete(() => print('Future.value() 03 whenComplete!'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
5. Future.error(Object error, [StackTrace stackTrace])

      error 主要建立一個異常狀态的 Future;

Future.error(ArgumentError.notNull('Input'));
Future.error('Future error01')
    .then((val) => print('Future.error01 result = $val'))
    .catchError((val) => print(val));
Future.error('Future error02')
    .then((val) => print('Future.error02 result = $val'))
    .catchError((val) => print(val))
    .whenComplete(() => print('Future.error03 whenComplete!'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
6. Future.microtask(FutureOr computation())

      microtask 比較特殊,會建立一個微隊列事件的 Future,Dart 的異步任務隊列主要包括 Event Queue 普通事件隊列和 Microtask Queue 微事件隊列,其中 Microtask Queue 的執行優先級更高,Future 預設是 Event Queue 普通隊列事件,小菜會在後面的部落格中進一步研究;

Future.microtask(() => print('Future.microtask() 01'));
Future.microtask(() {
  print('Future.microtask() 02');
  return 'Future.microtask() 02 result!';
}).then((val) => print(val)).whenComplete(() => print('Future.microtask() 02 whenComplete!'));
Future.microtask(() => print('Future.microtask() 03'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)

Future Static Methods

1. any(Iterable> futures)

      靜态方法 any() 是 Futures 數組中完成第一個 Future 的回調監聽,包括成功回調 then() 和異常回調 catchError(),其中第一個 Future 完成之後,并不影響其他的 Future 執行;

Future.any([
  Future.delayed(Duration(seconds: 4)).then((val) => 4),
  Future.delayed(Duration(seconds: 2)).then((val) => '2'),
  Future.delayed(Duration(seconds: 3)).then((val) => null),
]).then((val) => print(val));

Future.any([
  Future.error(ArgumentError.notNull('Input')),
  Future.error('Future error01').then((val) => print('Future.error01 result = $val')).catchError((val) => print(val)),
  Future.error('Future error02').then((val) => print('Future.error02 result = $val')).catchError((val) => print(val))
      .whenComplete(() => print('Future.error03 whenComplete!'))
]).then((val) => print('Future.any() --> then()'))
    .catchError((val) => print('Future.any() --> catchError() --> $val'))
    .whenComplete(() => print('Future.any() whenComplete!'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
2. doWhile(FutureOr action())

      靜态方法 doWhile() 可以用來執行循環任務,隻有當傳回内容是 false 或異常時停止;

var i = 0;
Future.doWhile(() {
  ++i;
  return Future.delayed(Duration(seconds: 2), () {
    print('Future.doWhile() $i, CurrentTime = ${DateTime.now().millisecondsSinceEpoch}');
    return i < 6;
  }).then((val) {
    print(val);
    return val;
  });
}.then((val) => print('Future.doWhile -> then() -> $val'))
    .whenComplete(() => print('Future.doWhile -> whenComplete()'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
3. forEach(Iterable elements, FutureOr action(T element))

      靜态方法 forEach() 用來周遊執行 elements 中各 item,不止于單一資料類型;

Future.forEach([
  1,
  Future(() => print('Future.forEach() 01')),
  Future(() {
    print('Future.forEach() 02');
    return 'Future.forEach() 02 result!';
  }).then((val) => print(val)),
  'Hello Flutter!',
  Future(() {
    print('Future.forEach() 03');
    return 'Future.forEach() 03 result!';
  }).then((val) => print(val))
      .whenComplete(() => print('Future.forEach() 03 whenComplete!'))
], (val) => print(val))
    .then((val) => print('Future.forEach() -> then() -> $val'))
    .whenComplete(() => print('Future.forEach() -> whenComplete()'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
4. wait(Iterable> futures, {bool eagerError: false, void cleanUp(T successValue)})

      靜态方法 wait() 用來等待多個 Futures 完成之後再執行,并收集結果,其中 Futures 時按延遲或其他順序執行,隻有所有的 Futures 結束之後會按 Futures 數組收集;

Future.wait([
  Future.delayed(Duration(seconds: 4)).then((val) {
    print('Future -> 4');
    return 4;
  }).whenComplete(() => print('Future -> 4 whenComplete!')),
  Future.delayed(Duration(seconds: 2)).then((val) {
    print('Future -> 2.toString()');
    return '2';
  }).whenComplete(() => print('Future -> 2.toString() whenComplete!')),
  Future.delayed(Duration(seconds: 3)).then((val) {
    print('Future -> null');
    return null;
  }).whenComplete(() => print('Future -> null whenComplete!')),
]).then((val) => print(val))
    .catchError((val) => print('Future.wait() --> catchError() --> $val'))
    .whenComplete(() => print('Future.wait() whenComplete!'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)

      a. Future.wait() 隻會捕獲 Futures 中第一個異常,且目前 Future 未進行捕獲,即:Future 中都進行了 catchError 則不會進入 wait().catchError();

Future.wait([
  Future.delayed(Duration(seconds: 4)).then((val) {
    print('Future -> 4');
    return 4;
  }).whenComplete(() => print('Future -> 4 whenComplete!')),
  Future.error('Future error01')
      .then((val) => print('Future.error01 result = $val'))
      .catchError((val) => print(val)),
  Future.error(ArgumentError.notNull('Input')),
  Future.error('Future error02')
      .then((val) => print('Future.error02 result = $val'))
      .catchError((val) => print(val))
      .whenComplete(() => print('Future.error02 whenComplete!'))
]).then((val) => print('Future.wait() --> then()'))
    .catchError((val) => print('Future.wait() --> catchError() --> $val'))
    .whenComplete(() => print('Future.wait() whenComplete!'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)

      b. wait() 但異常捕獲時機與 eagerError 參數相關,eagerError = true 時,Futures 中第一個傳回異常時 wait() 立即捕獲;eagerError = false 時,需等 Futures 全部執行結束之後才會捕獲;

eagerError: true           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)

      c. Futures 中出現異常時,cleanUp 會給每項正常執行的 Future 進行清理操作,傳遞給 cleanUp 的參數為每個正常執行項的傳回内容;

Future.wait([
  Future.delayed(Duration(seconds: 4)).then((val) {
    print('Future -> 4');
    return 4;
  }).whenComplete(() => print('Future -> 4 whenComplete!')),
  Future.error('Future error01')
      .then((val) => print('Future.error01 result = $val'))
      .catchError((val) => print(val)),
  Future.error(ArgumentError.notNull('Input')),
  Future.delayed(Duration(seconds: 2)).then((val) {
    print('Future -> 2.toString()');
    return '2';
  }),
  Future.error('Future error02')
      .then((val) => print('Future.error02 result = $val'))
      .catchError((val) => print(val))
      .whenComplete(() => print('Future.error02 whenComplete!')),
], cleanUp: (val) => print('Future.wait() --> cleanUp --> $val'))
    .then((val) => print('Future.wait() --> then()'))
    .catchError(
        (val) => print('Future.wait() --> catchError() --> $val'))
    .whenComplete(() => print('Future.wait() whenComplete!'));           
Flutter 90: 圖解 Dart 單線程實作異步處理之 Future (一)
Dart Future 案例嘗試

      小菜對 Dart 異步的認知還不完全,接下來會繼續嘗試 await-async 以及 EventLoop 執行順序等;如有錯誤和遺漏請多多指導!

來源: 阿策小和尚