【Flutter 1-13】Flutter手把手教程Dart語言——非同步、Future、Stream、async、await詳解
作者 | 弗拉德
來源 | 弗拉德(公眾號:fulade_me)
非同步
Dart 程式碼庫中有大量返回Future
或Stream
物件的函式,這些函式都是非同步的,它們會在耗時操作執行完畢前直接返回而不會等待耗時操作執行完畢。
async
和await
關鍵字用於實現非同步程式設計,並且讓你的程式碼看起來就像是同步的一樣。
Future
可以通過下面兩種方式,獲得Future
執行完成的結果:
- 使用
async
和await
; - 使用
Future API
;
使用async
和await
的程式碼是非同步的,但是看起來有點像同步程式碼。例如,下面的程式碼使用await
等待非同步函式的執行結果。
await lookUpVersion();
必須在帶有async
關鍵字的非同步函式中使用 await
:
Future checkVersion() async {
var version = await lookUpVersion();
// 使用 version 繼續處理邏輯
}
儘管非同步函式可以處理耗時操作,但是它並不會等待這些耗時操作完成,非同步函式執行時會在其遇到第一個 await
表示式的時候返回一個Future
物件,然後等待await
表示式執行完畢後繼續執行。
使用try
、catch
以及finally
來處理使用await
導致的異常:
try { version = await lookUpVersion(); } catch (e) { // 無法找到版本時做出的反應 }
你可以在非同步函式中多次使用await
關鍵字。例如,下面程式碼中等待了三次函式結果:
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
await
表示式的返回值通常是一個Future
物件;
如果不是的話也會自動將其包裹在一個Future
物件裡。Future
物件代表一個"承諾",await
表示式會阻塞直到需要的物件返回。
如果在使用await
時導致編譯錯誤,請確保await
在一個非同步函式中使用。例如,如果想在main()
await
,那麼main()
函式就必須使用async
關鍵字標識。
Future main() async {
checkVersion();
print('在 Main 函式中執行:版本是 ${await lookUpVersion()}');
}
宣告非同步函式
定義非同步函式只需在普通方法上加上async
關鍵字即可。
將關鍵字async
新增到函式並讓其返回一個Future
物件。假設有如下返回String
物件的方法:
String lookUpVersion() => '1.0.0';
將其改為非同步函式,返回值是Future
:
Future<String> lookUpVersion() async => '1.0.0';
注意,函式體不需要使用Future API
。如有必要,Dart
會建立Future
物件。
如果函式沒有返回有效值,需要設定其返回型別為 Future<void>
Stream
Stream
也是用於接收非同步事件資料,和Future
不同的是,它可以接收多個非同步操作的結果(成功或失敗)。 也就是說,在執行非同步任務時,可以通過多次觸發成功或失敗事件來傳遞結果資料或錯誤異常。Stream
常用於會多次讀取資料的非同步任務場景,如網路內容下載、檔案讀寫等。舉個例子:
Stream.fromFutures([
// 1秒後返回結果
Future.delayed(new Duration(seconds: 1), () {
return "hello 1";
}),
// 丟擲一個異常
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒後返回結果
Future.delayed(new Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){
});
上面的程式碼依次會輸出:
hello 1
Error
hello 3