异步生成器使用内部队列来处理同步的next、throw和return方法调用。
我试图构建一种情况,该队列对于迭代本身的成功是必需的。因此,我正在寻找一些情况,即手动实现异步迭代接口而无需自定义重新实现队列是不够的。
下面是一个例子,但不是很好,因为没有保持一般的时间一致性,但迭代结果在每一步都是正确的:
function aItsFactory() {
let i = 1;
return {
async next() {
if(i > 5) return Promise.resolve({ value: void 0, done: true });
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${i++}`).then(x => x.json());
return Promise.resolve({ value: res, done: false });
},
[Symbol.asyncIterator]() {
return this;
}
}
}
const ait = aItsFactory();
// general time consistency is lost, because e.g. the fourth call
// is started with the previous three and it could end before the others.
// But the 'i' state is correctly shared so the fifth call
// is correctly requesting the element number five to the source
// and the last call will correctly receive { done: true }
;(async () => {
ait.next();
ait.next();
ait.next();
ait.next();
console.log(await ait.next()); // { done: false, value: { userId: 1, id: 5, title: ... } }
console.log(await ait.next()); // { done: true, value: undefined }
})();
可以说,如果没有适当的队列,迭代概念本身就会丢失。那是因为活动的并行下一个调用。
无论如何,我想找一些例子,也是一些琐碎的例子,它们清楚地表明异步生成器是创建格式良好的异步迭代的更好方法,而不是手动实现异步迭代接口。
- - - 编辑 - - -
让我们谈谈一个改进的情况:
function aItsFactory() {
let i = 1;
let done = false;
return {
async next() {
if (done) return Promise.resolve({
done: true,
value: undefined
});
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${i++}`).then(x => x.json());
if (Object.keys(res).length === 0) { // the jsonplaceholder source is out of bounds
done = true;
return Promise.resolve({
done: true,
value: undefined
});
} else {
return Promise.resolve({
done: false,
value: res
});
};
},
[Symbol.asyncIterator]() {
return this;
}
}
}
const ait = aItsFactory();
// now lot of sync call to 'ait.next'
这里的done
分辨率是完全异步的。从异步迭代的角度来看,代码是错误的,因为每个next
调用都应该被强制到await
前一个的结果,以知道它是否是最后一次有效的迭代。在这种情况下,当前next
应该什么都不做,立即返回Promise.resolve({done:true, value:undefined})
。这要归功于同步next
调用队列。
但在实践中,越界、ait.next()
重复调用的主要风险是一些无用的 AJAX 请求。不要误会,我不是说我们可以视而不见。关键是异步迭代本身的每一步都不会被破坏。
我希望看到一种情况,不是太不切实际,如果所有下一个调用都没有排队,迭代本身可能会在每一步受到损害。