问题描述
async *[Symbol.asyncIterator](){
var promise;
while (true){
promise = this.#HEAD.promise;
this.size--;
this.#HEAD.next ? this.#HEAD = this.#HEAD.next
: this.#LAST = void 0;
yield await promise;
};
};
假设我不想使用 async / await
抽象,那么我如何仅使用 promise 来实现相同的功能?
我天真地尝试了
*[Symbol.asyncIterator](){
var promise;
while (true){
promise = this.#HEAD.promise;
this.size--;
this.#HEAD.next ? this.#HEAD = this.#HEAD.next
: this.#LAST = void 0;
promise.then(yield);
};
};
但它返回undefined
;推测 yield
不是函数。我查看了 this 问题,但它与生成器无关,也不涉及 yield
。有没有办法实现这个?
编辑: yield await promise
在异步生成器中似乎很浪费。请改用 yield promise
。查看 T.J. 下的评论群众回答。
解决方法
异步迭代器必须为结果对象({value,done}
形式的对象)生成承诺。你不能在非async
生成器中使用promise作为yield
的操作数,因为你给yield
的操作数变成了value
在结果对象中,而不是结果对象本身。也就是说,当你这样做时:
yield 42;
...在一个 async
生成器函数中,它为 {value: 42,done: false}
生成一个 promise(使用 TypeScript 符号 Promise<{value: 42,done: false}>
)。如果你这样做:
yield somePromise;
...在 non-async
生成器函数中,它生成 {value: somePromise,done: false}
(TS: {value: Promise,done: false}
)。这不是定义 asyncIterator
函数返回的内容。它必须返回 {value,done}
对象的承诺,而不是非承诺对象。
因此,如果您想避免使用 async
/await
,您至少有两个选择:
-
定义您的对象,使其不是异步可迭代的,而是可迭代的,并且它产生的值是
{value: Promise,done: boolean}
。 -
将其定义为异步可迭代并且不要使用
yield
。显式编写next
方法。
我肯定会为语义选择#2。如果没有关于您的对象的更多信息,很难准确显示,但大致如下:
[Symbol.asyncIterator](){
let current = this.#HEAD;
return {
next() {
if (/*done condition*/) {
return Promise.resolve({done: true});
}
return current.promise.then(value => {
current = current.next; // or whatever
return {value,done: false};
});
}
};
}
或者,如果您希望异步迭代器对象具有标准原型,请将其放在可以重用的地方:
const asyncIteratorPrototype =
Object.getPrototypeOf(
Object.getPrototypeOf(
(async function *(){}).prototype
)
);
然后:
[Symbol.asyncIterator](){
let current = this.#HEAD;
return Object.assign(Object.create(asyncIterator),{
next() {
if (/*done condition*/) {
return Promise.resolve({done: true});
}
return current.promise.then(value => {
current = current.next; // or whatever
return {value,done: false};
});
}
});
}