Dart 中的异步 API -- Future 和 Stream 以及 await/async

本文最后更新于 2021年4月4日 晚上

本文主要讲 Dart 中的异步 API.

关于 Future 和 Stream 的概念

在 Dart 的帮助文档中有这两个.

实际上在 Dart 的异步编程中, 主要涉及的就是单线程模型和 Isolate. Future 和 Stream 只是异步编程工具 API.

Future API 和 async/await

A Future represents a computation that doesn’t complete immediately. Where a normal function returns the result, an asynchronous function returns a Future, which will eventually contain the result. The future will tell you when the result is ready.

Dart 中的异步编程, 当某个函数或方法返回 Future<T> 类型时, 可以使用两套机制来操作, 一套是 async/await, 一套是 Future 本身带的 API(thencatchError 等).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

void main() {
print('开始');
execute();
print('执行完');
runApp(ListViewInsideScrollViewApp());
}

Future<void> execute() async {
print('进入');
final str = await delayOneSec();
print(str);
}

Future<String> delayOneSec() {
final oneSec = Duration(seconds: 1);
return Future.delayed(oneSec, () {// 内部就是需要延时执行的代码
return 'Hello world';
});
}

// 输出顺序是:
开始
进入
执行完
Hellow World

通过上面的代码来梳理 Futureasync/await 的使用规则:

  1. 针对 Future 类型返回值的函数, 外界可以直接将它当作是异步代码调用(无需 await), 并假设执行到它的时候是直接往下走的(而实际上是在它内部遇到 await 后才将控制返回到调用函数继续执行)
  2. await 只能在 async 函数或方法中使用.
  3. 如果使用 Future API 的话, 在 then 块中始终都要提供参数, 如果是 Future<void> , 则需要使用 _ 来表示参数.

Promise 的 API 类似, 在 Future 的 API 中可以将多个异步操作使用 then 来连接, 以达到顺序执行的目的(就相当于连续 await 多个异步操作一个道理, 只是写法不同罢了).

另外还可以等待多个异步操作结束, 这个就只能使用 Future 的异步 API wait 了:

1
2
3
Future.wait([expensiveA(), expensiveB(), expensiveC()])
.then((List responses) => chooseBestResponse(responses, moreInfo))
.catchError(handleError);

但任意一个异步操作抛出错误的话, 则就会进入 catchError 块中.

注意:

即便是最先完成的异步操作就产生了错误, 但进入错误捕捉块的时刻也是当最晚的一个异步操作执行完之后!

Stream

A stream is a sequence of asynchronous events. It is like an asynchronous Iterable—where, instead of getting the next event when you ask for it, the stream tells you that there is an event when it is ready.

Stream 就是异步事件流, 感觉和 Rx 有点类似.

Stream 中提供了许多操作符可供使用, 需要探索.

有两大类的 Stream:

  • 单一观察类型: 即这种流中的元素用到一起才可以构成一个整体, 当再次观察时可能就会错过一些之前的数据了. 这样整个流就可能没有任何实际意义.
  • 广播类型: 就是任何时候开始观察都可以获取到独立的事件, 比如一次鼠标点击等. 并且只要流还健在, 就可以随时监听或取消监听.

Stream 就是一个可观察的异步事件流 API.

杂项

async*: 用在含有 yield 的函数或方法上.

yield 的作用就是生成一个枚举器, 当外部请求下一个元素的时候, 枚举器就提供一个元素, 而不是传统地一次性将元素全部返回, 这样就实现了集合的”懒加载”.

需要看看关于 Event loop 的内容.


Dart 中的异步 API -- Future 和 Stream 以及 await/async
https://blog.rayy.top/2019/01/06/2019-29-dart-future-stream/
作者
貘鸣
发布于
2019年1月6日
许可协议