Gestion des rappels asynchrones à appel multiples

learnyounode node.js avec learnyounode . J'ai un problème avec JUGGLING ASYNC . Le problème est décrit comme suit:
Vous recevez trois URL comme arguments de ligne de commande. Vous êtes censé faire des http.get() pour obtenir des données à partir de ces URL et les imprimer dans le même ordre que leur ordre dans la liste des arguments. Voici mon code:

 var http = require('http') var truecount = 0; var printlist = [] for(var i = 2; i < process.argv.length; i++) { http.get(process.argv[i], function(response) { var printdata = ""; response.setEncoding('utf8'); response.on('data', function(data) { printdata += data; }) response.on('end', function() { truecount += 1 printlist.push(printdata) if(truecount == 3) { printlist.forEach(function(item) { console.log(item) }) } }) }) } 

Voici les questions que je ne comprends pas: j'essaie de stocker les données complétées dans response.on('end', function(){}) pour chaque url à l'aide d'un dictionnaire. Cependant, je ne sais pas comment obtenir l'url pour ce http.get() . Si je peux faire une variable locale dans http.get() , ce serait génial, mais je pense que chaque fois que je déclare une variable comme var url , elle indiquera toujours la dernière URL. Comme il est global et qu'il continue de se mettre à jour via la boucle. Quelle est la meilleure façon pour moi de stocker ces données complétées comme valeur avec la clé égale à l'url?

C'est ainsi que je vais résoudre le problème.

 #!/usr/bin/env node var http = require('http'); var argv = process.argv.splice(2), truecount = argv.length, pages = []; function printUrls() { if (--truecount > 0) return; for (i = 0; i < pages.length; i++) { console.log(pages[i].data + '\n\n'); } } function HTMLPage(url) { var _page = this; _page.data = '### [URL](' + url + ')\n'; http.get(url, function(res) { res.setEncoding('utf8'); res.on('data', function(data) { _page.data += data; }); res.on('end', printUrls); }); } for (var i = 0; i < argv.length; i++) pages.push(new HTMLPage(argv[i])); 

Il ajoute les requêtes à un tableau au début de chaque requête, de cette manière une fois terminé, je peux itérer très bien à travers les réponses en sachant qu'elles sont dans l'ordre correct.

En ce qui concerne le traitement asynchrone, je trouve beaucoup plus facile de penser à chaque processus comme étant un début et une fin concrets. Si vous souhaitez que l'ordre des demandes soit conservé, la saisie doit être effectuée lors de la création de chaque processus, puis vous renvoyez à cet enregistrement à la fin. C'est seulement alors que vous pouvez garantir que vous avez des choses dans le bon ordre.

Si vous étiez désespéré d'utiliser votre méthode ci-dessus, vous pouvez définir une variable à l'intérieur de votre fermeture de rappel et l'utiliser pour stocker les urls, de sorte que vous ne finiriez pas avec la dernière URL qui écrase vos variables. Si vous parlez ainsi, vous augmenterez considérablement vos frais généraux lorsque vous devez utiliser vos URL de process.argv pour accéder à chaque réponse dans cet ordre. Je ne le conseillerai pas.

J'ai abordé ce défi un peu différemment. Je crée un ensemble de fonctions qui appellent http.get et les invoque immédiatement avec leur contexte spécifique. Les flux écrivent à un objet où la clé est le port du serveur auquel ce flux est pertinent. Lorsque l'événement final est déclenché, il ajoute à ce serveur au tableau complété – lorsque ce tableau est plein, il itère et écho dans l'ordre d'origine, les serveurs ont été donnés.

Il n'y a pas de bon moyen, mais il y a probablement une douzaine ou plus de façons. Je voulais partager le mien.

 var http = require('http'), request = [], dataStrings = {}, orderOfServerInputs = []; var completeResponses = []; for(server in process.argv){ if(server >= 2){ orderOfServerInputs[orderOfServerInputs.length] = process.argv[server].substr(-4); request[request.length] = function(thisServer){ http.get(process.argv[server], function(response){ response.on("data", function(data){ dataStrings[thisServer.substr(-4)] = dataStrings[thisServer.substr(-4)] ? dataStrings[thisServer.substr(-4)] : ''; //if not set set to '' dataStrings[thisServer.substr(-4)] += data.toString(); }); response.on("end", function(data){ completeResponses[completeResponses.length] = true; if(completeResponses.length > 2){ for(item in orderOfServerInputs){ serverNo = orderOfServerInputs[item].substr(-4) console.log(dataStrings[serverNo]); } } }); }); }(process.argv[server]); } } 

L'Expression de fonction appelée immédiatement (IIFE) pourrait être une solution à votre problème. Il nous permet de nous lier à une valeur spécifique, dans votre cas, de l'URL qui reçoit la réponse. Dans le code ci-dessous, je lie la variable i à l' index et, si l'URL reçoit la réponse, l'index de la liste d'impression sera mis à jour. Pour plus d'informations, consultez ce site

 var http = require('http') var truecount = 0; var printlist = []; for(var i = 2; i < process.argv.length; i++) { (function(index){ http.get(process.argv[index], function(response) { response.setEncoding('utf8'); response.on('data', function(data) { if (printlist[index] == undefined) printlist[index] = data; else printlist[index]+= data; }) response.on('end', function() { truecount += 1 if(truecount == 3) { printlist.forEach(function(item) { console.log(item) }) } }) }) })(i) }