1
votes

Comment exécuter une fonction basée sur la promesse en série

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!


6 commentaires

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


4 Réponses :


-2
votes

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


0 commentaires

1
votes

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


0 commentaires

3
votes

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


0 commentaires

0
votes

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


0 commentaires