Dart庫中包含許多返回 Future 或 Stream 對象的函數。這些函數是異步的:它們在啓動一個耗時操作(例如I/O操作)後返回,而不是等待該耗時操作完成。
async 和 await 關鍵字支持異步編程,它們使你編寫異步代碼看起來跟編寫同步代碼一樣。
處理Futures
當你需要一個已經完成了的Future對象的結果時,你有兩個選擇:
- 使用async 和 await
- 使用Future API,參見文檔:in the library tour
使用async 和 await 的代碼是異步的,但是看起來像是同步代碼。例如,這裏的代碼使用 await 來等待一個異步函數的結果:
await lookUpVersion();
要使用 await ,代碼必須在一個異步函數內部—一個被標記爲 async 的函數:
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
注意: 雖然異步函數可能執行耗時的操作,但它不會等待這些操作。相反,異步函數只在遇到第一個await表達式時執行( details )。然後它會返回一個Future對象,盡在 await 表達式完成之後才恢復執行。
在使用 await 的代碼處通過 try、catch 和 finally 來處理錯誤以及清理工作。
try {
version = await lookUpVersion();
} catch (e) {
// React to inability to look up the version
}
你可以在一個異步函數裏多多次使用 await 。例如:
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
在 await 表達式中,表達式的值通常是一個 Future ;如果不是,那麼他的值會被自動的封裝爲一個 Future 對象。這個 Future 對象會保證返回一個對象。 await 表達式的值就是那個返回的對象。 await 表達式使得執行暫停,直到結果對象可用。
如果你在使用 await 時出現一個編譯時錯誤,確保 await 是在一個異步函數中。例如,要在你的APP的 main() 函數中使用 await ,那麼 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> 。
處理流(Streams)
當你需要從一個流(Stream)獲取值時,你有兩個選擇:
- 使用 async 和一個異步 for 循環( await for )
- 使用 Stream API,in the library tour
一個異步 for 循環的格式如下:
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}
上面的代碼中 expression 的類型必須是 Stream,執行過程如下:
1. 會一直等待直到流發射一個值
2. 使用發射的值作爲變量,執行for循環的循環體
3. 重複 1 和 2 ,直到流被關閉
要停止對流的監聽,你可以使用一個 break 和 return 語句,它可以終止 for 循環並且解除對流的訂閱。
當實現一個異步的for循環時如果出現一個編譯時錯誤,確保 await for 在一個異步函數中。例如,在你的APP的 main() 函數中使用一個異步 for 循環, main() 的函數體必須被標記爲 async :
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}
關於異步編程的更多信息,請參考:dart:async.
生成器(Generators)
當你需要延遲產生一些數據序列時,使用生成器函數。Dart 支持兩種生成器函數:
要實現一個 同步 生成器函數,將函數體標記爲 sync* ,並且使用yield 語句來發送數據。
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
要實現一個 異步 生成器函數,將函數體標記爲 async* ,並且使用 yield 語句來發送數據。
Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
如果你的生成器是遞歸的,你可以使用 yield* 來提升它的性能:
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
可調用的類
要允許像函數一樣調用Dart類的實例,實現 call() 方法即可:
class WannabeFunction {
call(String a, String b, String c) => '$a $b $c!';
}
main() {
var wf = new WannabeFunction();
var out = wf("Hi","there,","gang");
print('$out');
}
Isolates
大多數計算機,即使是在移動平臺上,都擁有多核心CPU。要充分使用所有的這些核心,開發人員傳統上使用共享內存的線程併發執行。然而,共享狀態的併發執行容易出錯,並且可能導致代碼複雜化。
所有Dart代碼都在 isolates 中運行,而不是線程。每一個 Isolate 都有它自己的內存堆,這就確保沒有任何 Isolate 狀態可以被其他任意 isolate 訪問。
關於 Isolates 的更多信息, dart:isolate library documentation 。