我从后端服务获取数据,一次获得20个结果。我想隐藏这个实现细节并创建一个生成器,只要我需要它们就会保留返回记录(当它们可用时)。
天真的实施:
function* getEndlessRecords(fetchingFunction) {
const batchSize = 20;
// endless loop:
for (let offset = 0; true; offset += batchSize) {
fetchingFunction(offset, batchSize)
.then(records => {
for (let i=0; i < records.length; i++) {
yield records[i]; // THIS DOESN'T WORK!!!
}
})
}
}
(可能存在拼写错误 - 这是简化代码)
我理解为什么这不起作用(yield
适用于最里面的函数),但我似乎找不到一个很好的方法来创建围绕异步函数的生成器。
生成器是否可以使用异步函数的输出?
从ES2018开始,您可以使用异步生成器功能:
async function* getEndlessRecords(fetchingFunction) {
const batchSize = 20;
// endless loop:
for (let offset = 0; true; offset += batchSize) {
const records = await fetchingFunction(offset, batchSize);
for (let i=0; i < records.length; i++) {
yield records[i];
}
}
}
你使用async
(不是for-await-of
)在for-of
函数中消耗它:
for await (const value of getEndlessRecords(/*...*/)) {
// Do something with `value`
}
...或者只是通过调用它的next
方法并等待结果:
let g = getEndlessRecords(/*...*/);
let result;
while (!(result = await g.next()).done) {
console.log(result.value);
}
...或者当然,在非async
函数中,你会在then
的结果上使用g.next()
。
在ES2018的异步生成器函数语法之前,您必须手动编写生成器而不是使用function*
语法。这样做可以说是错误的(不允许对%GeneratorPrototype%进行任何扩展)相当容易。正确地这样做是相当尴尬的,因为%GeneratorPrototype%没有可公开访问的符号,你必须去发现它。