[TOC]
Dart庫中有非常多的函數返回Future對象或Stream對象。這些函數是異步的:在可能耗時的操作(例如I/O)操作的語句之后不等到操作執行完成就返回。
async和await關鍵字支持異步編程,允許您編寫類似于同步代碼的異步代碼。
## 處理Futures
當你需要一個完整的Futures的結果時,你有兩個選擇:
* 使用async和await
* 使用Future的API,如[庫的引導]中描述的一樣
使用async和await的代碼雖然是異步的,但是看起來很像同步代碼。例如,以下代碼使用await來等待異步函數執行的結果:
~~~
await lookUpVersion();
~~~
要使用await必須是對一個使用async標注的異步函數:
~~~
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
~~~
>注意:盡管異步函數可能執行耗時的操作,但它不會等待這些操作。相反,異步函數一直執行直到遇到第一個await表達式([查看詳細信息])。然后它返回一個Futures的對象,只有在await表達式完成之后才恢復執行。
>
Use try, catch, and finally to handle errors and cleanup in code that uses await:
使用try,catch和finally來處理使用await的代碼中的錯誤:
~~~
try {
version = await lookUpVersion();
} catch (e) {
// React to inability to look up the version
}
~~~
你可以在異步函數中多次使用await。例如,以下代碼執行了三次await來獲取函數的結果。
~~~
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
~~~
在await表達式中,表達式的值通常是一個Future對象。如果不是,那么這個值將被自動包裝成Future。Futrue對象指示返回結果一定是一個對象。表達式的值就是被返回的對象。await表達式會讓程序執行掛起,直到返回的對象可用。
***如果在使用await時出現編譯時錯誤,請確保await在異步函數中*** 。例如,要在應用程序的main()函數中使用wait, main()的主體必須標記為async:
~~~
Future main() async {
checkVersion();
print('In main: version is ${await lookUpVersion()}');
}
~~~
## 聲明異步函數
異步函數是函數體被用async修飾符標記的函數。
向函數中添加async關鍵字將使其返回一個Future。例如,請思考下例中返回一個字符串的同步函數:
~~~
String lookUpVersion() => '1.0.0';
~~~
如果你將他改變成一個異步函數,他的返回值將是一個Future:
~~~
Future<String> lookUpVersion() async => '1.0.0';
~~~
注意,函數的主體不需要使用Future的API。如果需要,Dart將創建Future的對象。
如果您的函數沒有返回一個有用的值,那么將其返回Future\<void>類型。
## 處理流(Stream)
當您需要從Stream獲取值時,您有兩個選擇:
* 使用async和異步的for循環(await for)
* 使用Stream API,如[庫的引導]中的描述
>注意:在使用await for之前,請確保它使代碼更清晰,并且您確實希望等待流(Stream)的所有結果。例如,您通常不應該為UI事件偵聽器使用await,因為UI框架會發送無窮無盡的事件流。
>
異步for循環有以下形式:
~~~
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}
~~~
表達式的值必須具有Stream類型。執行過程如下:
1. 等待流發出值。
2. 執行for循環的主體,并將變量設置為發出的值。
3. 重復1和2,直到流關閉。
要停止偵聽流,您可以使用break或return語句,該語句將跳出for循環,并從流中取消訂閱。
如果在實現異步for循環時出現編譯時錯誤,請確保await在異步函數中。例如,要在應用程序的main()函數中使用異步For循環,main()的主體必須標記為async:
~~~
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}
~~~
有關異步編程的更多信息,請參閱[庫引導文檔]的dart:async部分。還可以參閱文章[Dart語言異步支持:階段1]和[Dart語言異步支持:階段2]和[Dart語言規范]。