Dart 简明教程 - 09 - Asynchrony support

451 阅读4分钟

本系列教程大多翻译自 Dart 官网,因本人英语水平有限,可能有些地方翻译不准确,还请各位大佬斧正。如需转载请标明出处,谢绝 CSDN 爬虫党。

Asynchrony support(异步支持)

Dart 库充满了各种返回未来(Future,类似于 JavaScript 的 Promise)或流(Stream)的对象。这些函数是异步的:无需一直等待可能耗时的操作完成(如 I/O ),期间可以执行其他操作,再该函数处理完后就返回结果。

asyncawait 关键字支持异步编程。允许你编写类似于同步代码的异步代码。

处理 Futures(Handing Futures)

当你需要一个在未来才返回的结果时,你有两种选择:

使用 asyncawait 编写的代码,是移步的,但是看起来像同步的:

await lookUpVersion();

await 必须在被 async 标记的函数里使用:

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

Note: 即使 async 函数可能进行耗时的操作,但无需等待那些操作。相反的,async 函数只在遇到第一个 await 表达式 才执行。然后返回一个 Future 对象,然后直到 await 表达式执行完毕才继续运行。

await 可以搭配 trycatchfinally 来使用。

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

async 函数里,可以多次使用 await

Future checkVersion() async {
  var entrypoint = await findEntrypoint();
  var exitCode = await runExecutable(entrypoint, args);
  await flushThenExit(exitCode);
}

await 表达式里,表达式的值通常是一个 Future;如果不是,该值也会自动包裹在 Future 里。这个 Future 对象指示了一个会返回对象的承诺(promise)。await 表达式的值是一个返回的对象。await 表达式会使所处的函数执行暂停,直到对象返回为止。

确保在 async 函数里面使用 await,否则会报错。 例如:你想在main()中使用 awiat,那 main() 的函数体必须标记为 async

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

声明一个异步函数(Declaring async functions)

异步函数就是用 async 标识符标记的函数体。

添加 async关键字,让函数返回一个 Future。例如:看看这个返回一个字符串的同步函数:

String lookUpVersion() => '1.0.0';

如果你想把它变为异步函数,比如,它会返回一个 Future,因为这个操作可能耗时,所以在未来才能实现:

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

注意到函数体并不需要使用 Future 提供的 API。如果需要的话,Dart 会自动创建 Future 对象。如果你的函数不返回任何有效的值,确保返回的类型是 FUture<void>

更多关于使用 Future、async 和 await 的介绍,请移步 asynchronous programming codelab

处理流(Handling Streams)

当你需要从 Stream 那里获取值,你有两个选择:

  • 使用 async 和异步循环(asynchronous for loopawait for));
  • 使用 Stream 提供的 API

Note: 在使用 await for 之前,确保代码是干净的,并且你真的想等待所有的 stream 结果。例如,你不应该对 UI 事件监听使用 await for,因为 UI 框架会无止境的发送流体事件(streams of events)。

异步循环如下所示:

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

表达式的值必须有 Stream 类型。会按如下规则执行:

  1. 等待 stream 触发值;
  2. 执行循环体,并对触发的值进行赋值;
  3. 重复 1、2 步骤,直到 stream 关闭;

要停止对 stream 的监听,你可以使用 breakreturn 语句,这些可以打断循环并取消对 stream 的事件订阅。

如果当你使用异步循环的时候,收到一个编译错误,确保 await forasync 函数中。例如,你想在main()中使用 awiat for,那 main() 的函数体必须标记为 async

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

更多关于异步编程的详情,请查阅 dart:async 章节。

系列文章:

Dart 简明教程 - 01 - Concepts & Variables
Dart 简明教程 - 02 - Functions
Dart 简明教程 - 03 - Operators
Dart 简明教程 - 04 - Control flow statements
Dart 简明教程 - 05 - Exceptions
Dart 简明教程 - 06 - Classes
Dart 简明教程 - 07 - Generics
Dart 简明教程 - 08 - Libraries and visibility
Dart 简明教程 - 09 - Asynchrony support
Dart 简明教程 - 10 - Generators & Isolates & Typedefs & Metadata...