在 Javascript 中同步链接可变数量的共享资源的承诺

Chaining a variable number of promises synchronously that share a resource in Javascript

我正在尝试使用 Chrome lighthouse 检查列表中的多个 url。我可以用 url 成功地使用他们的示例代码来做到这一点。

function launchChromeAndRunLighthouse(url, opts, config = null) {
  return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => {
    opts.port = chrome.port;
    return lighthouse(url, opts, config).then(results => {
      // use results.lhr for the JS-consumeable output
      // https://github.com/GoogleChrome/lighthouse/blob/master/types/lhr.d.ts
      // use results.report for the HTML/JSON/CSV output as a string
      // use results.artifacts for the trace/screenshots/other specific case you need (rarer)
      return chrome.kill().then(() => results.lhr)
    });
  });
}

不过,我想检查多个 url。这将需要使用 chromeLauncher.launch 创建浏览器 window,在每个 url 上执行 lighthouse 函数,然后最后在 window 上调用 chrome.kill() , 在 return 结果之前。

最初,我尝试使用 Promise.all

解决这个问题
  return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => {
    opts.port = chrome.port;

    const checks = urls.map((url) => {
      console.log('checking', url)
      return lighthouse(url, opts, config)
    })

    return Promise.all(checks).then((results) => {
      return chrome.kill().then(() => results)
    })
  });

但是由于每次调用 lighthouse 都使用共享资源,他们必须等待上一次调用 return 才能继续,而 Promise.all 尝试并行进行所有灯塔调用,然后解决。这不适用于单个共享浏览器资源。

然后我尝试使用减速器进行试验,将 chrome 启动器承诺作为初始值。

  const checks = urls.reduce((previous, url) => {
    return previous.then((previousValue) => {
      return lighthouse(url, opts, config)
    })
  }, chromeLauncher.launch({chromeFlags: opts.chromeFlags}))

  checks
    .then((results) => {
      console.log('something')
      return chrome.kill()
    })
    .then((results) => results.lhr)

但这在调用 lighthouse 函数时也不起作用,但我认为这是同步调用承诺链的正确方法。

有没有人对我出错的地方有任何建议,或者我还可以尝试什么?

使用异步等待:

const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

async function launchChromeAndRunLighthouse(urls, opts, config = null) {
    const chrome = await chromeLauncher.launch({chromeFlags: opts.chromeFlags})
    opts.port = chrome.port;
    const results = [];
    for (const url of urls) {
         results.push(await lighthouse(url, opts, config));
    }
    await chrome.kill();
    return results;
}

const opts = {
    chromeFlags: ['--show-paint-rects']
};

// Usage:
const urls = ['http://www.google.de', 'http://www.heise.de'];
launchChromeAndRunLighthouse(urls, opts).then(results => {
    console.log(results);
});

经典:

const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

function launchChromeAndRunLighthouse(urls, opts, config = null) {
    return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => {
        opts.port = chrome.port;

        const results = [];
        return urls.reduce((p, url) => {
            return p.then(() => {
                return lighthouse(url, opts, config).then((data) => {
                    results.push(data);
                    return results;
                });
            });
        }, Promise.resolve())
            .then(() => chrome.kill())
            .then(() => results)
    });
}

const opts = {
    chromeFlags: ['--show-paint-rects']
};

// Usage:
const urls = ['http://www.google.de', 'http://www.heise.de'];
launchChromeAndRunLighthouse(urls, opts).then(results => {
    console.log(results);
})

或者使用像 Bluebird 这样的库:

const Promise = require('bluebird');
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

function launchChromeAndRunLighthouse(urls, opts, config = null) {
    return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => {
        opts.port = chrome.port;

        return Promise.mapSeries(urls, url => lighthouse(url, opts, config))
            .then((results) => chrome.kill().then(() => results))
    });
}

const opts = {
    chromeFlags: ['--show-paint-rects']
};

// Usage:
const urls = ['http://www.google.de', 'http://www.heise.de'];
launchChromeAndRunLighthouse(urls, opts).then(results => {
    console.log(results);
});