異步支持

2021-09-13 09:49 更新

Dart 庫中包含許多返回 Future 或 Stream 對象的函數(shù). 這些函數(shù)在設(shè)置完耗時任務(wù)(例如 I/O 曹組)后, 就立即返回了,不會等待耗任務(wù)完成。 使用 async 和 await 關(guān)鍵字實現(xiàn)異步編程。 可以讓你像編寫同步代碼一樣實現(xiàn)異步操作。


處理 Future

可以通過下面兩種方式,獲得 Future 執(zhí)行完成的結(jié)果:

  • 使用 async 和 await.
  • 使用 Future API,具體描述,參考 庫概覽.

使用 async 和 await 關(guān)鍵字的代碼是異步的。 雖然看起來有點像同步代碼。 例如,下面的代碼使用 await 等待異步函數(shù)的執(zhí)行結(jié)果。

await lookUpVersion();

要使用 await , 代碼必須在 異步函數(shù)(使用 async 標記的函數(shù))中:

Future checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}

提示: 雖然異步函數(shù)可能會執(zhí)行耗時的操作, 但它不會等待這些操作。 相反,異步函數(shù)只有在遇到第一個 await 表達式(詳情見)時才會執(zhí)行。 也就是說,它返回一個 Future 對象, 僅在await表達式完成后才恢復(fù)執(zhí)行。

使用 try, catch, 和 finally 來處理代碼中使用 await 導(dǎo)致的錯誤。

try {
  version = await lookUpVersion();
} catch (e) {
  // React to inability to look up the version
}

在一個異步函數(shù)中可以多次使用 await 。 例如,下面代碼中等待了三次函數(shù)結(jié)果:

var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);

在 await 表達式 中, 表達式 的值通常是一個 Future 對象; 如果不是,這是表達式的值會被自動包裝成一個 Future 對象。 Future 對象指明返回一個對象的承諾(promise)。 await 表達式 執(zhí)行的結(jié)果為這個返回的對象。 await 表達式會阻塞代碼的執(zhí)行,直到需要的對象返回為止。

如果在使用 await 導(dǎo)致編譯時錯誤, 確認 await 是否在一個異步函數(shù)中。 例如,在應(yīng)用的 main() 函數(shù)中使用 await , main() 函數(shù)的函數(shù)體必須被標記為 async :

Future main() async {
  checkVersion();
  print('In main: version is ${await lookUpVersion()}');
}


聲明異步函數(shù)

函數(shù)體被 async 標示符標記的函數(shù),即是一個_異步函數(shù)_。 將 async 關(guān)鍵字添加到函數(shù)使其返回Future。 例如,考慮下面的同步函數(shù),它返回一個 String :

String lookUpVersion() => '1.0.0';

例如,將來的實現(xiàn)將非常耗時,將其更改為異步函數(shù),返回值是 Future 。

Future<String> lookUpVersion() async => '1.0.0';

注意,函數(shù)體不需要使用Future API。 如有必要, Dart 會創(chuàng)建 Future 對象。

如果函數(shù)沒有返回有效值, 需要設(shè)置其返回類型為 Future<void> 。


處理 Stream

當需要從 Stream 中獲取數(shù)據(jù)值時, 可以通過一下兩種方式:

  • 使用 async 和 一個 異步循環(huán) (await for)。
  • 使用 Stream API, 更多詳情,參考 in the library tour。

提示: 在使用 await for 前,確保代碼清晰, 并且確實希望等待所有流的結(jié)果。 例如,通常不應(yīng)該使用 await for 的UI事件偵聽器, 因為UI框架會發(fā)送無窮無盡的事件流。

一下是異步for循環(huán)的使用形式:

await for (varOrType identifier in expression) {
  // Executes each time the stream emits a value.
}

上面 表達式 返回的值必須是 Stream 類型。 執(zhí)行流程如下:

  1. 等待,直到流發(fā)出一個值。
  2. 執(zhí)行 for 循環(huán)體,將變量設(shè)置為該發(fā)出的值
  3. 重復(fù)1和2,直到關(guān)閉流。

使用 break 或者 return 語句可以停止接收 stream 的數(shù)據(jù), 這樣就跳出了 for 循環(huán), 并且從 stream 上取消注冊。 **如果在實現(xiàn)異步 for 循環(huán)時遇到編譯時錯誤, 請檢查確保 await for 處于異步函數(shù)中。** 例如,要在應(yīng)用程序的 main() 函數(shù)中使用異步 fo r循環(huán), main() 函數(shù)體必須標記為 async` :

Future main() async {
  // ...
  await for (var request in requestServer) {
    handleRequest(request);
  }
  // ...
}

有關(guān)異步編程的更多信息,請參考 dart:async 部分。 同時也可參考文章 Dart Language Asynchrony Support: Phase 1 和 Dart Language Asynchrony Support: Phase 2, 以及 Dart language specification 。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號