ES9 引入了 异步遍历器 和 异步生成器,使得在处理异步数据时更为方便。这些特性解决了在异步编程中需要按需获取数据的情况,特别适用于网络请求、大型数据流、文件读取等场景。接下来,我们将详细总结这些特性,并与同步遍历器和同步生成器进行对比。
1. 异步遍历器(Async Iterators)
1.1 用法
异步遍历器(Async Iterators)允许你通过 for await...of 语句异步地遍历对象,通常用于从异步源(如网络请求、数据库、文件流等)中获取数据。与同步遍历器不同,异步遍历器返回的是 Promise,因此需要使用 await 来获取值。
const asyncIterable = {
async *[Symbol.asyncIterator]() {
yield 1;
yield 2;
yield 3;
}
};
(async () => {
for await (const value of asyncIterable) {
console.log(value); // 1, 2, 3
}
})();
- 语法:for await (const value of asyncIterable)
- asyncIterable 必须实现 Symbol.asyncIterator 方法,返回一个异步的迭代器对象。
1.2 使用场景
异步遍历器通常用于处理需要异步等待的流式数据或需要按需获取的数据,如从 API 请求数据、读取大文件、流式处理等。
例子:模拟异步 API 请求
async function fetchData() {
return [1, 2, 3, 4, 5];
}
const asyncIterable = {
async *[Symbol.asyncIterator]() {
const data = await fetchData();
for (let item of data) {
yield item;
}
}
};
(async () => {
for await (const value of asyncIterable) {
console.log(value); // 1, 2, 3, 4, 5
}
})();
在此例子中,fetchData() 模拟一个异步 API 请求,数据在异步迭代器中逐步返回。
2. 异步生成器(Async Generators)
2.1 用法
异步生成器是结合了 生成器 和 异步操作 的强大工具。它使用 async function* 语法,允许生成异步迭代的结果。每次调用 yield 时,生成器会返回一个 Promise,并且生成器本身也返回一个异步迭代器。
async function* asyncGenerator() {
yield 1;
yield 2;
yield 3;
}
(async () => {
for await (const value of asyncGenerator()) {
console.log(value); // 1, 2, 3
}
})();
- 语法:async function* asyncGenerator() { yield value }
- asyncGenerator() 是一个异步生成器函数,每次 yield 返回一个异步值。
2.2 使用场景
异步生成器适用于需要处理异步流数据的场景,如读取大文件、实时数据流处理等。它使得异步操作和生成器的组合更为自然,并且支持按需生成数据。
例子:异步生成器处理实时数据流
async function* asyncDataStream() {
const dataStream = [10, 20, 30, 40, 50]; // 模拟数据流
for (let data of dataStream) {
await new Promise(resolve => setTimeout(resolve, 1000)); // 模拟异步操作
yield data;
}
}
(async () => {
for await (const data of asyncDataStream()) {
console.log(data); // 输出 10, 20, 30, 40, 50,每隔1秒
}
})();
在这个例子中,asyncDataStream() 模拟了一个每隔 1 秒返回数据的异步生成器。
3. 异步遍历器与异步生成器的区别
3.1 异步遍历器(Async Iterators)
- 异步遍历器是对象实现了 Symbol.asyncIterator 方法的对象。
- 它的目标是异步迭代数据,返回一个 Promise,并通过 for await...of 进行异步遍历。
const asyncIterable = {
async *[Symbol.asyncIterator]() {
yield 1;
yield 2;
yield 3;
}
};
异步遍历器适合需要异步访问的数据源,例如流式数据或异步操作。
3.2 异步生成器(Async Generators)
- 异步生成器是一个特殊的异步函数,使用 async function* 语法来定义。
- 每次调用 yield 时,返回一个异步的值,并且能够逐步生成数据。
async function* asyncGenerator() {
yield 1;
yield 2;
yield 3;
}
异步生成器更灵活,可以在内部执行多个异步操作,返回一个 Promise。
3.3 异步生成器与异步遍历器的关系
- 异步生成器本质上是一种实现了异步迭代器接口的特殊函数。通过 async function* 语法定义的异步生成器可以直接用于 for await...of 循环。
- 异步遍历器是异步生成器返回的迭代器,具有 next() 和 return() 方法,能够控制异步数据的获取。
4. 同步生成器与异步生成器的区别
4.1 同步生成器
- 同步生成器使用 function* 定义,通过 yield 返回数据。当使用 for...of 循环时,它会逐步返回每个值。
function* syncGenerator() {
yield 1;
yield 2;
yield 3;
}
for (const value of syncGenerator()) {
console.log(value); // 1, 2, 3
}
4.2 异步生成器
异步生成器与同步生成器类似,但它处理的是异步操作,返回的是 Promise。异步生成器使用 async function* 语法定义,通过 yield 返回异步数据。
async function* asyncGenerator() {
yield 1;
yield 2;
yield 3;
}
(async () => {
for await (const value of asyncGenerator()) {
console.log(value); // 1, 2, 3
}
})();
4.3 区别总结
| 特性 | 同步生成器 | 异步生成器 |
|---|---|---|
| 定义语法 | function* | async function* |
| 数据获取 | 同步返回 | 异步返回(Promise) |
| 适用场景 | 同步数据流,简单的生成任务 | 异步数据流,网络请求、大文件等 |
for...of 使用 | 可直接使用 | 使用 await for...of |
5. 总结
- 异步遍历器 通过实现 Symbol.asyncIterator 接口,可以异步地遍历数据,适合需要逐步异步处理的数据。
- 异步生成器 结合了生成器和异步操作,适合处理需要生成异步数据流的场景。
- 与同步生成器和同步遍历器相比,异步版本的生成器和遍历器能够处理异步操作,返回 Promise,并且可以与 await 结合使用。 这两个特性极大地简化了异步流处理的代码,提高了代码的可读性和可维护性,特别是在处理大数据、文件流或需要等待的异步操作时。