给定一个像这样的循环:
for await(let line of readFileLineByLine('./long-file.txt')) {
const interestingFacts = await processLine(line);
}
在
readFileLineByLine
返回AsyncGenerator的地方,它将在await processLine
返回之前或之后开始处理第二行吗? (假设processLine
完成之前第二行已准备就绪)如果没有,那么如何并行化呢? (以便可以同时处理许多行)
最佳答案
您的for await
循环是以下内容的语法糖:
let generator = readFileLineByLine();
while (true) {
let promise = generator.next();
let item = await promise;
if (item.done)
break;
let line = item.value;
await processLine(line)
}
因此答案是肯定的,在
readLine(nextLine)
完成之前processLine(previousLine)
不会启动。如果要使两个函数不相互依赖,则一种选择是使
readFileLineByLine
不异步,即仅yield
待处理的Promise。正常使用此生成器,将then(processLine)
附加到每个promise并等待它们:let promises = [];
for (let promise of readFileLineByLinePending())
promises.push(promise.then(processLine))
await Promise.all(promises)
这是一个演示:
async function delay(n) {
return new Promise(res => setTimeout(res, n))
}
async function processLine(s) {
console.log('process BEGIN:', s)
await delay(300);
console.log('process END:', s)
}
async function* readFileLineByLine() {
for (let i = 0; i < 6; i++) {
console.log('read BEGIN', i)
await delay(500);
let t = await 'line' + i;
console.log('read END', i)
yield t;
}
}
function* readFileLineByLinePending() {
for (let i = 0; i < 6; i++) {
console.log('readPending BEGIN', i)
let t = delay(500).then(() => {
console.log('readPending END', i);
return 'line' + i;
});
yield t;
}
}
async function main() {
console.time('async gen')
for await(let line of readFileLineByLine())
await processLine(line)
console.log('----------------------------------------')
console.timeEnd('async gen')
console.log('----------------------------------------')
console.time('sync gen')
let promises = [];
for (let promise of readFileLineByLinePending())
promises.push(promise.then(processLine))
await Promise.all(promises)
console.log('----------------------------------------')
console.timeEnd('sync gen')
console.log('----------------------------------------')
}
main().then(() => console.log('done'))
.as-console-wrapper {max-height:100% !important; top:0;}