JavaScript 异步迭代器

摘要:在本教程中,您将学习有关 JavaScript 异步迭代器的知识,这些迭代器允许您按顺序访问异步数据。

JavaScript 异步迭代器简介

ES6 引入了 迭代器 接口,允许您按顺序访问数据。迭代器非常适合访问同步数据源,如 数组集合映射

迭代器接口的主要方法是 next(),它返回 {value, done} 对象,其中 done 是一个布尔值,表示是否已到达序列的末尾,而 value 是序列中产生的值。

同步数据意味着序列中的下一个 valuedone 状态在 next() 方法返回时是已知的。

除了同步数据源之外,JavaScript 通常还需要访问异步数据源,例如 I/O 访问。对于异步数据源,迭代器的 valuedone 状态在 next() 方法返回时通常是未知的。

为了处理异步数据源,ES2018 引入了异步迭代器(或异步迭代器)接口。

异步迭代器类似于迭代器,只是它的 next() 方法返回一个 promise,该 promise 解析为 {value, done} 对象。

以下说明了实现迭代器接口的 Sequence 类。(查看 迭代器教程,了解有关如何实现 Sequence 类的更多信息。)

class Sequence {
    constructor(start = 0, end = Infinity, interval = 1) {
            this.start = start;
            this.end = end;
            this.interval = interval;
        }
        [Symbol.iterator]() {
            let counter = 0;
            let nextIndex = this.start;
            return {
                next: () => {
                    if (nextIndex <= this.end) {
                        let result = {
                            value: nextIndex,
                            done: false
                        }
                        nextIndex += this.interval;
                        counter++;
                        return result;
                    }
                    return {
                        value: counter,
                        done: true
                    };
                }
            }
        }
}Code language: JavaScript (javascript)

为了使此 Sequence 类异步化,您需要对其进行如下修改

  • 使用 Symbol.asyncIterator 而不是 Symbol.iterator
  • next() 方法返回 Promise。

以下代码将 Sequence 类转换为 AsyncSequence

class AsyncSequence {
    constructor(start = 0, end = Infinity, interval = 1) {
            this.start = start;
            this.end = end;
            this.interval = interval;
        }
        [Symbol.asyncIterator]() {
            let counter = 0;
            let nextIndex = this.start;
            return {
                next: async () => {
                    if (nextIndex <= this.end) {
                        let result = {
                            value: nextIndex,
                            done: false
                        }
                        nextIndex += this.interval;
                        counter++;

                        return new Promise((resolve, reject) => {
                            setTimeout(() => {
                                resolve(result);
                            }, 1000);
                        });
                    }
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            resolve({
                                value: counter,
                                done: true
                            });
                        }, 1000);

                    });
                }
            }
        }
}Code language: JavaScript (javascript)

AsyncSequence 每隔 1 秒返回序列中的下一个数字。

for await...of 语句

为了迭代异步可迭代对象,ES2018 引入了 for await...of 语句

for await (variable of iterable) {
    // statement
}
Code language: JavaScript (javascript)

由于我们只能在 async 函数中使用 await 关键字,因此我们可以创建一个异步 IIFE,该函数使用 AsyncSequence 类,如下所示

(async () => {

    let seq = new AsyncSequence(1, 10, 1);

    for await (let value of seq) {
        console.log(value);
    }

})();
Code language: JavaScript (javascript)

输出(每个数字在每秒之后返回)

1
2
3
4
5
6
7
8
9
10Code language: JavaScript (javascript)

下表说明了迭代器和异步迭代器之间的差异

#迭代器异步迭代器
众所周知的符号Symbol.iteratorSymbol.asyncIterator
next() 返回值是{value, done }Promise 解析为 {value, done}
循环语句for...offor await...of
本教程是否有帮助?