J'essaie d'exécuter la fonction node js Lighthouse en série (une à la fois) avec un tableau d'URL. Mon problème est que chaque fois que je boucle dans le tableau, Lighthouse exécute toutes les URL à la fois, ce qui, j'imagine, est problématique si vous avez un très grand éventail d'URL.
Le code:
for(let url of urls) { 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 => { return chrome.kill().then(() => results.lhr) }); }); } } launchChromeAndRunLighthouse('https://example.com', opts).then(results => { // Use results! });
Veuillez aider! Et merci pour votre temps!
4 Réponses :
Juste pour exécuter votre code comme test, nous utiliserons async / await et IIFE
Ensuite, créera une fonction qui mettra toute notre requête dans un tableau de promesses non résolues, afin que nous puissions l'utiliser avec Promise.all ()
Vous devez réécrire le code dans quelque chose comme ceci:
(async() => { const promisesToExecute = []; const launchChromeAndRunLighthouse = async (url, opts, config = null) => { const chrome = await return chromeLauncher.launch({chromeFlags: opts.chromeFlags}); opts.port = chrome.port; promisesToExecute.push(lighthouse(url, opts, config)); } const results = await Promise.all(promisesToExecute); for(const result of results) { const resolvedResult = await result.kill(); // here you can access your results.lhr console.log(resolvedResult.lhr); } })()
Veuillez noter , ce code n'a pas été testé, il peut donc y avoir des problèmes avec kill ()
sur le résultat. Mais l'objectif principal est de répondre à votre question et d'expliquer comment exécuter les promesses.
De plus, si vous ne souhaitez pas exécuter toutes les promesses en même temps, vous pouvez utiliser Promise.waterfall avec un package npm, comme ceci
Je crois que j'ai compris. Ce que j'ai fait est ci-dessous. Veuillez continuer à envoyer des commentaires si vous pensez que c'est faux.
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 => { return chrome.kill().then(() => results.lhr) }); }); }; async function launchAudit(urls) { for (let url of urls) { await launchChromeAndRunLighthouse(url, opts).then(results => { // Use results! }); }; }; launchAudit(urls);
Votre réponse est correcte mais elle peut être améliorée. Puisque vous avez accès à async
et await
, vous devez l'utiliser pleinement pour rendre votre code plus propre:
async function launchChromeAndRunLighthouse (url, opts, config = null) { const chrome = await chromeLauncher.launch({chromeFlags: opts.chromeFlags}); opts.port = chrome.port; const { lhr } = await lighthouse(url, opts, config); await chrome.kill(); return lhr; } async function launchAudit (urls) { for (const url of urls) { const results = await launchChromeAndRunLighthouse(url, opts); // Use results! }; } launchAudit(urls);
Une variante de la réponse de Patric Roberts (qui devrait être la réponse acceptée).
Je me demandais s'il était nécessaire de tuer Chrome à chaque itération.
const lighthouse = require('lighthouse'); const chromeLauncher = require('chrome-launcher'); function launchChromeAndRunLighthouse(sites, opts, config = null) { return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => { opts.port = chrome.port; const siteResults = []; return new Promise((resolve, reject) => { // batch async functions. // C/O https://stackoverflow.com/questions/43082934/how-to-execute-promises-sequentially-passing-the-parameters-from-an-array const runBatch = async (iterable, action) => { for (const x of iterable) { await action(x) } } // func to run lighthouse const doLightHouse = (site) => new Promise((resolve, reject) => { lighthouse(site, opts, config).then(results => { siteResults.push(results.lhr); resolve(); }); }); // go go go runBatch(sites, doLightHouse).then(d => { chrome.kill().then((result) => { resolve(siteResults) }) }); }); }); } const opts = { chromeFlags: ['--show-paint-rects'], onlyCategories: ['performance'] }; const sites = ['https://www.example.com', 'https://www.test.com'] launchChromeAndRunLighthouse(sites, opts).then(results => { // Use results! console.log(results); });
Vous ne devriez pas mettre une déclaration de fonction dans une boucle
for
. Malgré cela, votre code n'utilise pas réellement la boucle, il récupère simplement'https://example.com'
à plusieurs reprises ...Wow désordonné, prenez la fonction à l'extérieur et envisagez d'utiliser une méthode forEach ou une autre méthode de tableau. Jetez un œil à async / await. Vous devriez toujours privilégier les fonctions d'ordre supérieur au lieu de boucles comme for ... of.
@squeekyDave
forEach ()
ne va pas corriger l'itération asynchrone. En fait, cela va rendre la mise en œuvre correcte plus difficile.@PatrickRoberts Je ne dis pas que forEach réparera tout, comme je l'ai dit, considérez d'autres méthodes de tableau. Traiter également le code asynchrone est beaucoup plus facile avec async / await donc je pense qu'il devrait essayer ça.
Je suis désolé gang ... ce code a été massacré ci-dessus. Je l'ai fait fonctionner. Je publierai la solution sous peu. Merci pour votre participation!
Double possible de Utilisation de async / await avec une boucle forEach