### 異步
1. Dart 添加了一些新的語言特性用于支持異步編程。最通常使用的特性是 async 方法和 await 表達式。Dart 庫大多方法返回 Future 和 Stream 對象。這些方法是異步的:它們在設置一個可能的耗時操作(比如 I/O 操作)之后返回,而無需等待操作完成
2. 當你需要使用 Future 來表示一個值時,你有兩個選擇。
* 使用 async 和 await
* 使用 Future API
3. 同樣的,當你需要從 Stream 獲取值的時候,你有兩個選擇。
* 使用 async 和一個異步的 for 循環 (await for)
* 使用 Stream API
4. 使用 async 和 await 的代碼是異步的,不過它看起來很像同步的代碼。比如這里有一段使用 await 等待一個異步函數結果的代碼:
`await lookUpVersion()`
5. 要使用 await,代碼必須用 await 標記
~~~
checkVersion() async {
var version = await lookUpVersion();
if (version == expectedVersion) {
// Do something.
} else {
// Do something else.
}
}
~~~
6. 你可以使用 try, catch, 和 finally 來處理錯誤并精簡使用了 await 的代碼。
~~~
try {
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 4044);
} catch (e) {
// React to inability to bind to the port...
}
~~~
7. ***聲明異步函數***
* 一個異步函數是一個由 async 修飾符標記的函數。雖然一個異步函數可能在操作上比較耗時,但是它可以立即返回-在任何方法體執行之前。
~~~
checkVersion() async {
// ...
}
lookUpVersion() async => /* ... */;
~~~
* 在函數中添加關鍵字 async 使得它返回一個 Future,比如,考慮一下這個同步函數,它將返回一個字符串。
* String lookUpVersionSync() => '1.0.0';
* 如果你想更改它成為異步方法-因為在以后的實現中將會非常耗時-它的返回值是一個 Future 。
* Future lookUpVersion() async => '1.0.0';
* ***請注意函數體不需要使用 Future API,如果必要的話 Dart 將會自己創建 Future 對象***
8. ***使用帶 future 的 await 表達式***
* 一個 await表達式具有以下形式
`await expression`
* 在異步方法中你可以使用 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 標記:
~~~
```
main() async {
checkVersion();
print('In main: version is ${await lookUpVersion()}');
}
```
~~~
9. ***結合 streams 使用異步循環***
* 一個異步循環具有以下形式:
~~~
await for (variable declaration in expression) {
// Executes each time the stream emits a value.
}
~~~
* `表達式`的值必須有Stream 類型(流類型)。執行過程如下:
* 在 stream 發出一個值之前等待
* 執行 for 循環的主體,把變量設置為發出的值。
* 重復 1 和 2,直到 Stream 關閉
* 如果要停止監聽 stream ,你可以使用 break 或者 return 語句,跳出循環并取消來自 stream 的訂閱 。
* 如果一個異步 for 循環沒有正常運行,請確認它是一個異步方法。 比如,在應用的 main() 方法中使用異步的 for 循環時,main() 的方法體必須被 async 標記。
~~~
main() async {
...
await for (var request in requestServer) {
handleRequest(request);
}
...
}
~~~