javascript - 异步生成器类卡在无限循环javascript上
问题描述
我正在尝试使以下异步生成器工作:
class MyIterator {
constructor(m) {
this.collection = m;
}
async *[Symbol.iterator]() {
for (let item of this.collection) {
const resultItem = await Promise.resolve(item)
console.log("item: ", resultItem)
yield resultItem
}
}
}
(async () => {
const iterator = new MyIterator([1,2,3])
let times = 0
for await (let thing of iterator) {
console.log("thing: ", thing)
// this is here to avoid an infinite loop
times++
if (times > 1000) break
}
})()
但它最终陷入无限循环,并且thing
始终未定义。
item: 1
thing: undefined
item: 2
thing: undefined
item: 3
thing: undefined (x999)
我尝试过类似的代码,但这次没有这种Promise/async
行为,它似乎工作得很好。
class MyIterator {
constructor(m) {
this.collection = m;
}
*[Symbol.iterator]() {
for (let item of this.collection) {
console.log("item: ", item)
yield item
}
}
}
const iterator = new MyIterator([1,2,3])
for (let thing of iterator) {
console.log("thing: ", thing)
}
item: 1
thing: 1
item: 2
thing: 2
item: 3
thing: 3
解决方案
该for await..of
构造将尝试迭代异步迭代器。
使用@@asyncIterator
众所周知的符号定义异步迭代器:
class MyIterator {
constructor(m) {
this.collection = m;
}
async *[Symbol.asyncIterator]() { //<-- this is async
for (let item of this.collection) {
const resultItem = await Promise.resolve(item)
//console.log("item: ", resultItem)
yield resultItem
}
}
}
(async () => {
const iterator = new MyIterator([1,2,3])
let times = 0
for await (let thing of iterator) {
//no infinite loop
console.log("thing: ", thing)
}
})()
for await..of
还可以使用产生承诺的普通迭代:
const promiseArray = [Promise.resolve("a"), Promise.resolve("b"), Promise.resolve("c")];
(async function() {
for await(const item of promiseArray) {
console.log(item);
}
})()
尝试创建作为异步方法/函数的常规迭代器不起作用。
如果你想保留你@@iterator
定义的方法,最好的选择是让它产生 Promise:
class MyIterator {
constructor(m) {
this.collection = m;
}
*[Symbol.iterator]() { // not async
for (let item of this.collection) {
yield Promise.resolve(item); //produce a promise
}
}
}
(async () => {
const iterator = new MyIterator([1,2,3])
let times = 0
for await (let thing of iterator) {
console.log("thing: ", thing)
}
})()
虽然,如果任何承诺拒绝,这可能是一个不好的做法:
const wait = (ms, val) =>
new Promise(res => setTimeout(res, ms, val));
const fail = (ms, val) =>
new Promise((_, rej) => setTimeout(rej, ms, val));
const arr = [
wait(100, 1),
wait(150, 2),
fail(0, "boom"),
wait(200, 3)
];
(async function(){
try {
for await (const item of arr) {
console.log(item);
}
} catch (e) {
console.error(e);
}
})()
/* result in the browser console:
Uncaught (in promise) boom
1
2
boom
*/
但是,请注意,这些之间存在语义差异:
- 常规迭代器产生一个 IteratorResult - 一个具有
value
和done
属性的对象。
const syncIterable = {
[Symbol.iterator]() {
return {
next() {
return {value: 1, done: true}
}
}
}
}
const syncIterator = syncIterable[Symbol.iterator]();
console.log("sync IteratorResult", syncIterator.next());
- 异步生成器为 IteratorResult 生成承诺
const asyncIterable = {
[Symbol.asyncIterator]() {
return {
next() {
return Promise.resolve({value: 2, done: true});
}
}
}
}
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
asyncIterator.next().then(result => console.log("async IteratorResult", result));
- 最后,产生承诺的迭代器将有一个 IteratorResult ,其中
value
是一个承诺:
const promiseSyncIterable = {
[Symbol.iterator]() {
return {
next() {
return {value: Promise.resolve(3), done: true}
}
}
}
}
const promiseSyncIterator = promiseSyncIterable[Symbol.iterator]();
const syncPromiseIteratorResult = promiseSyncIterator.next();
console.log("sync IteratorResult with promise", syncPromiseIteratorResult);
syncPromiseIteratorResult.value
.then(value => console.log("value of sync IteratorResult with promise", value));
关于命名的旁注:MyIterator
不是迭代器。迭代器next()
是具有产生 IteratorResult 的方法的对象。您可以迭代的对象有一个@@iterator
(or @@asyncIterable
) 方法,它被称为可迭代的(或分别称为异步可迭代)。
推荐阅读
- reactjs - 向后端 Next.js - Next-Auth 发送 POST 请求时如何通过 cookie 验证用户?
- prometheus - 验证 prometheus 指标是否已更新
- python - 关闭 GitHub 问题时自动运行脚本
- docker - Windows Docker 文件:如何缓存 Chocolatey 安装?
- bash - 在 Heroku 上为 Sinatra 应用程序设置环境变量
- c# - ListView.HasUnevenRows 属性在 Xamarin.Forms.iOS 中不起作用
- android - AssertionError: Activity 永远不会变为请求状态“[DESTROYED, STARTED, RESUMED, CREATED]”(最后一个生命周期转换 =“PRE_ON_CREATE”)
- python - 我在 Pyspark 中使用 DataFrame 显示方法时出错
- flutter - 任何知道如何做这个颤振滑块?有现有的软件包吗?
- javascript - LCM功能练习