将同步代码插入异步

interject synchronous code into asynchoronous

我 运行 lighthouse cli 反对 ~50 个站点列表。我只是 运行 它在 .forEach 循环中,据我所知,它是阻塞的,也就是同步的。但是,我最终同时启动了 50 Chrome 个 Canary 实例。在我对这些事情的有限理解中,我认为线程是同步启动的,但是 node 可以将线程传递给内核并愉快地启动下一个线程。同样,这只是我对正在发生的事情的粗略理解。

我正在使用从某处抄袭的这个功能:

function launchChromeAndLighthouse(url, opts, config = null) {
  return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => {
    opts.port = chrome.port;
    return lighthouse(url, opts, config).then(results =>
      chrome.kill().then(() => results));
  });
}

我在循环中尝试了 nextTick

asyncFuncs().then( async (sites) => {
  sites.forEach( (site) => {
    process.nextTick(launchChromeAndRunLighthouse(site.url, opts))
  })
})

但这仍然会产生一堆 Chrome 个实例。如何在一个灯塔完成时暂停执行?

由于 launchChromeAndRunLighthouse() returns 承诺在完成时进行标记,如果您只想 运行 一次一个地连续显示它们,您可以切换到 for 循环并使用 await:

asyncFuncs().then( async (sites) => {
  for (let site of sites) {
    await launchChromeAndRunLighthouse(site.url, opts);
  }
});

如果您要收集所有结果:

asyncFuncs().then( async (sites) => {
    let results = [];
    for (let site of sites) {
      let r = await launchChromeAndRunLighthouse(site.url, opts);
      results.push(r);
    }
    return results;
}).then(results => {
    // all results here
}).catch(err => {
    // process error here
});

如果你想一次 运行 N chrome 个实例,这样它最初启动 N 个实例,然后每次完成一个,你启动下一个正在等待的,那就更多跟踪有多少实例正在 运行 很复杂。在这些答案中,有一个辅助函数调用 pMap()mapConcurrent() 可以为您做到这一点:


Bluebird Promise library also has concurrency control in its Promise.map() function.