Je rencontre un problème de flux de contrôle lorsqu'une application charge un grand nombre d'URL. J'utilise Caolan Async et le module de requête NPM.
Mon problème est que la réponse HTTP commence dès que la fonction est ajoutée à la file d'attente. Idéalement, je veux créer ma file d'attente et ne commencer à faire les demandes HTTP qu'au début de la file d'attente. Sinon, les callbacks commencent à se déclencher avant la file d'attente, ce qui entraîne sa fermeture prématurée.
var request = require('request') // https://www.npmjs.com/package/request
, async = require('async'); // https://www.npmjs.com/package/async
var myLoaderQueue = []; // passed to async.parallel
var myUrls = ['http://...', 'http://...', 'http://...'] // 1000+ urls here
for(var i = 0; i < myUrls.length; i++){
myLoaderQueue.Push(function(callback){
// Async http request
request(myUrls[i], function(error, response, html) {
// Some processing is happening here before the callback is invoked
callback(error, html);
});
});
}
// The loader queue has been made, now start to process the queue
async.parallel(queue, function(err, results){
// Done
});
Y a-t-il un meilleur moyen d'attaquer cela?
L'utilisation de boucles for
combinées à des appels asynchrones est problématique (avec ES5) et peut générer des résultats inattendus (dans votre cas, l'URL erronée est extraite).
Au lieu de cela, envisagez d'utiliser async.map()
:
async.map(myUrls, function(url, callback) {
request(url, function(error, response, html) {
// Some processing is happening here before the callback is invoked
callback(error, html);
});
}, function(err, results) {
...
});
Étant donné que vous avez plus de 1000 URL à récupérer, async.mapLimit()
peut également être utile.
Si vous êtes prêt à commencer à utiliser Bluebird
et Babel
pour utiliser promises
et ES7
async
/await
, vous pouvez procéder comme suit:
let Promise = require('bluebird');
let request = Promise.promisify(require('request'));
let myUrls = ['http://...', 'http://...', 'http://...'] // 1000+ urls here
async function load() {
try {
// map myUrls array into array of request promises
// wait until all request promises in the array resolve
let results = await Promise.all(myUrls.map(request));
// don't know if Babel await supports syntax below
// let results = await* myUrls.map(request));
// print array of results or use forEach
// to process / collect them in any other way
console.log(results)
} catch (e) {
console.log(e);
}
}
Je suis assez confiant que vous ressentez les résultats d'une erreur différente. Au moment où vos fonctions en file d'attente évaluent, j’ai été redéfini, ce qui peut donner l’apparence que vous avez manquée les premières URL. Essayez une petite fermeture lorsque vous modifiez les fonctions.
var request = require('request') // https://www.npmjs.com/package/request
, async = require('async'); // https://www.npmjs.com/package/async
var myLoaderQueue = []; // passed to async.parallel
var myUrls = ['http://...', 'http://...', 'http://...'] // 1000+ urls here
for(var i = 0; i < myUrls.length; i++){
(function(URLIndex){
myLoaderQueue.Push(function(callback){
// Async http request
request(myUrls[URLIndex], function(error, response, html) {
// Some processing is happening here before the callback is invoked
callback(error, html);
});
});
})(i);
}
// The loader queue has been made, now start to process the queue
async.parallel(queue, function(err, results){
// Done
});