小菜嘗試過 Future 和 Stream 實作 Dart 異步處理,但僅限于基本的使用,網上有很多相關的資料,小菜僅從初識者的角度學習了解 Dart 的實作的異步處理;
Dart 是單線程的!這點很重要,是不可變更的;但單線程的 Dart 是如何實作多線程的,這是很值得研究的;
小菜了解的異步操作來處理耗時任務的方式主要是兩種:一種是類似于 Java 的開啟多線程,并線上程間通信;另一種是類似于 Dart 的單線程和事件循環 Event Loop;其中 Event Loop 事件循環就是把一系列的(點選事件/滑動事件/網絡請求/ IO 事件等)事件存放在 Event Queue 隊列中,循環執行從 Event Loop 中擷取事件進行執行,直到清空隊列事件;

Future
Future Methods
Future 的應用主要涉及三種狀态,分别是未完成狀态(UnCompleted / Pending),完成成功(Completed with Data),完成失敗(Completed with Error);
當 Future 任務執行完成之後,通常需要一個回調,這個回調會立即執行,不會添加到事件隊列中,其中通過 then() 的成功回調來來監聽 Future 執行完成時擷取到的結果;通過 catchError() 異常回調來監聽 Future 執行失敗或者出現異常時的錯誤資訊;通過 whenComplete() 最終回調來擷取最終回調,不管成功還是失敗;
小菜做了一個不太嚴謹的對比,這三種狀态類似于 try-catch-finally,其中 try 對應 then() 成功回調,catch 對應 catchError() 異常回調,而 finally 對應 whenComplete() 最終回調;
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}'));
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!'));
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!'));
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}');
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!'));
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!'));
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'));
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!'));
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()'));
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()'));
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!'));
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!'));
b. wait() 但異常捕獲時機與 eagerError 參數相關,eagerError = true 時,Futures 中第一個傳回異常時 wait() 立即捕獲;eagerError = false 時,需等 Futures 全部執行結束之後才會捕獲;
eagerError: true
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!'));
小菜對 Dart 異步的認知還不完全,接下來會繼續嘗試 await-async 以及 EventLoop 執行順序等;如有錯誤和遺漏請多多指導!
來源: 阿策小和尚