異步
Dart 代碼庫中有大量返回Future
或Stream
對象的函數(shù)阅虫,這些函數(shù)都是異步的演闭,它們會在耗時操作執(zhí)行完畢前直接返回而不會等待耗時操作執(zhí)行完畢。
async
和await
關鍵字用于實現(xiàn)異步編程颓帝,并且讓你的代碼看起來就像是同步的一樣米碰。
Future
可以通過下面兩種方式,獲得Future
執(zhí)行完成的結果:
- 使用
async
和await
购城; - 使用
Future API
吕座;
使用async
和await
的代碼是異步的,但是看起來有點像同步代碼工猜。例如米诉,下面的代碼使用await
等待異步函數(shù)的執(zhí)行結果菱蔬。
await lookUpVersion();
必須在帶有async
關鍵字的異步函數(shù)中使用 await
:
Future checkVersion() async {
var version = await lookUpVersion();
// 使用 version 繼續(xù)處理邏輯
}
盡管異步函數(shù)可以處理耗時操作篷帅,但是它并不會等待這些耗時操作完成,異步函數(shù)執(zhí)行時會在其遇到第一個 await
表達式的時候返回一個Future
對象拴泌,然后等待await
表達式執(zhí)行完畢后繼續(xù)執(zhí)行魏身。
使用try
、catch
以及finally
來處理使用await
導致的異常:
try {
version = await lookUpVersion();
} catch (e) {
// 無法找到版本時做出的反應
}
你可以在異步函數(shù)中多次使用await
關鍵字蚪腐。例如箭昵,下面代碼中等待了三次函數(shù)結果:
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
await
表達式的返回值通常是一個Future
對象;
如果不是的話也會自動將其包裹在一個Future
對象里回季。Future
對象代表一個"承諾",await
表達式會阻塞直到需要的對象返回家制。
如果在使用await
時導致編譯錯誤正林,請確保await
在一個異步函數(shù)中使用。例如颤殴,如果想在main()
函數(shù)中使用await
觅廓,那么main()
函數(shù)就必須使用async
關鍵字標識。
Future main() async {
checkVersion();
print('在 Main 函數(shù)中執(zhí)行:版本是 ${await lookUpVersion()}');
}
聲明異步函數(shù)
定義異步函數(shù)只需在普通方法上加上async
關鍵字即可涵但。
將關鍵字async
添加到函數(shù)并讓其返回一個Future
對象杈绸。假設有如下返回String
對象的方法:
String lookUpVersion() => '1.0.0';
將其改為異步函數(shù),返回值是Future
:
Future<String> lookUpVersion() async => '1.0.0';
注意矮瘟,函數(shù)體不需要使用Future API
瞳脓。如有必要,Dart
會創(chuàng)建Future
對象澈侠。
如果函數(shù)沒有返回有效值劫侧,需要設置其返回類型為 Future<void>
Stream
Stream
也是用于接收異步事件數(shù)據(jù),和Future
不同的是哨啃,它可以接收多個異步操作的結果(成功或失敯辶伞)。 也就是說棘催,在執(zhí)行異步任務時劲弦,可以通過多次觸發(fā)成功或失敗事件來傳遞結果數(shù)據(jù)或錯誤異常。Stream
常用于會多次讀取數(shù)據(jù)的異步任務場景醇坝,如網(wǎng)絡內(nèi)容下載邑跪、文件讀寫等。舉個例子:
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