给定一个像这样的循环:

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;}

08-18 22:46