node.js多个asynchronous函数

var http = require('http'); var res = ["","",""]; for(i =2;i<5;i++){ http.get(process.argv[i],function(response){ response.setEncoding('utf8'); str = ""; count =i-2; response.on("data", function(data) { str = str.concat(data); }); response.on("end", function() { res[count] = str; console.log(count); console.log(res[count]); }); }); } while(true) { if(res[0]!==""&&res[1]!==""&&res[2]!=="") { console.log(res[0]); console.log(res[1]); console.log(res[2]); break; } } 

我将有三个URL作为前三个命令行参数。 我的工作是从每个URL的string中收集数据,并按命令行中显示的顺序将其打印到控制台。 现在代码不会打印任何东西,而且会陷入无限循环。 哪里不对?

代码中有两个问题。 首先,你有一个循环variables的闭包,使得值与你所期望的不同,正如guvinder372所解释的那样。 另请参阅讨论问题的答案 ,以及使用Function.bind解决问题的更好方法。

第二个问题是你最后设置while循环的方式。 该循环将持续运行,并且永远不会允许您的http.get的callback函数运行。 相反,如果其他响应已经进入,那么检查callback,一旦三个进来,打印输出。

 for(i =2;i<5;i++){ http.get(process.argv[i],function(response){ response.setEncoding('utf8'); str = ""; count =i-2; response.on("data", function(data) { str = str.concat(data); }); response.on("end", function() { //Check here if responses are in if(res[0]!==""&&res[1]!==""&&res[2]!=="") { } res[count] = str; console.log(count); console.log(res[count]); }); }); } 

问题是 – 在调用callback处理程序的时候,i的值已经达到了5,并且对于所有的callback处理程序执行,它将保持5。

您需要重构您的代码,以将我的值传递给该调用方法

 var http = require('http'); var res = ["","",""]; for(i =2;i<5;i++) { callBackDefiner(i) } function callBackDefiner( i ) { http.get(process.argv[i],function(response){ response.setEncoding('utf8'); str = ""; count =i-2; response.on("data", function(data) { str = str.concat(data); }); response.on("end", function() { res[count] = str; console.log(count); console.log(res[count]); }); }); } 

您不能等待响应,不能在for...loop执行多个http请求。 要以现代的方式编写这个代码,你需要一些新的构造/模式,比如Promise 。 然后您可以等待每个响应,收集响应,然后退出调用者。 作为一个例子,看看我的解决scheme的JavaScript客户端。 这也可以在Node.js做一些小小的工作,你只需要改变块函数ExecutionBlock的请求。

假设我们有一个我们想要发送给一些urls /或者不同url的数组的参数数组,我们将使用一个Promise.all构造来运行。

在下面的代码片段中尝试一下。

要了解如何将此解决scheme应用于Node.js请参阅我在此处的http get和post的实现,并在后面的内容中查看a,以获取asynchronous任务节点中更复杂的执行情况。

 var console = { log: function(s) { document.getElementById("console").innerHTML += s + "<br/>" } } // Simple XMLHttpRequest // based on https://davidwalsh.name/xmlhttprequest SimpleRequest = { call: function(what, response) { var request; if (window.XMLHttpRequest) { // Mozilla, Safari, ... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // state changes request.onreadystatechange = function() { if (request.readyState === 4) { // done if (request.status === 200) { // complete response(request.responseText) } else response(); } } request.open('GET', what, true); request.send(null); } } //PromiseAll var promiseAll = function(items, block) { var self = this; var promises = [], index = 0; items.forEach(function(item) { promises.push(function(item, i) { return new Promise(function(resolve, reject) { if (block) { block.apply(this, [item, index, resolve, reject]); } }); }(item, ++index)) }); return Promise.all(promises) }; //promiseAll // LP: deferred execution block var ExecutionBlock = function(item, index, resolve, reject) { SimpleRequest.call('https://icanhazip.com/', function(result) { if (result) { console.log("Response[" + index + "] " + result); resolve(result); } else { reject(new Error("call error")); } }) } arr = [1, 2, 3] promiseAll(arr, (item, index, resolve, reject) => { console.log("Making request [" + index + "]") ExecutionBlock(item, index, resolve, reject); }) .then((results) => { console.log(results) }) .catch((error) => { console.error(error) }); 
 <div id="console" />