|
当值是以异步的形式出现时,例如在 setTimeout 或者另一种延迟之后,就需要异步迭代。
最常见的场景是,对象需要发送一个网络请求以传递下一个值,稍后我们将看到一个它的真实示例。
要使对象异步迭代:
使用 Symbol.asyncIterator 取代 Symbol.iterator。
next() 方法应该返回一个 promise(带有下一个值,并且状态为 fulfilled)。
关键字 async 可以实现这一点,我们可以简单地使用 async next()。
我们应该使用 for await (let item of iterable) 循环来迭代这样的对象。
注意关键字 await。
作为开始的示例,让我们创建一个可迭代的 range 对象,与前面的那个类似,不过现在它将异步地每秒返回一个值。
我们需要做的就是对上面代码中的部分代码进行替换:
let range = {
from: 1,
to: 5,
[Symbol.asyncIterator]() { // (1)
return {
current: this.from,
last: this.to,
async next() { // (2)
// 注意:我们可以在 async next 内部使用 "await"
await new Promise(resolve => setTimeout(resolve, 1000)); // (3)
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
}
};
(async () => {
for await (let value of range) { // (4)
alert(value); // 1,2,3,4,5
}
})()
正如我们所看到的,其结构与常规的 iterator 类似:
为了使一个对象可以异步迭代,它必须具有方法 Symbol.asyncIterator (1)。
这个方法必须返回一个带有 next() 方法的对象,next() 方法会返回一个 promise (2)。
这个 next() 方法可以不是 async 的,它可以是一个返回值是一个 promise 的常规的方法,但是使用 async 关键字可以允许我们在方法内部使用 await,所以会更加方便。这里我们只是用于延迟 1 秒的操作 (3)。
我们使用 for await(let value of range) (4) 来进行迭代,也就是在 for 后面添加 await。它会调用一次 range[Symbol.asyncIterator]() 方法一次,然后调用它的 next() 方法获取值。
这是一个对比 Iterator 和异步 iterator 之间差异的表格:
Iterator 异步 iterator
提供 iterator 的对象方法 Symbol.iterator Symbol.asyncIterator
next() 返回的值是 任意值 Promise
要进行循环,使用 for..of for await..of
Spread 语法 ... 无法异步工作
需要常规的同步 iterator 的功能,无法与异步 iterator 一起使用。
例如,spread 语法无法工作:
alert( [...range] ); // Error, no Symbol.iterator
这很正常,因为它期望找到 Symbol.iterator,而不是 Symbol.asyncIterator。
for..of 的情况和这个一样:没有 await 关键字时,则期望找到的是 Symbol.iterator。
|
|