繁体   English   中英

node.js 多个异步函数

[英]node.js multiple asynchronous functions

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 中收集作为字符串的数据,并按照它们在命令行中出现的顺序将它们打印到控制台。 现在代码没有打印任何东西,它陷入了无限循环。 怎么了?

代码中有两个问题。 首先,您在循环变量上有一个闭包,这使得值与 guvinder372 解释的预期不同。 另见这个答案,其中讨论了这个问题,这个答案演示一种更好的方式使用来解决这个问题Function.bind

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

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

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

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

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 然后,您可以等待每个响应、收集响应并退出调用者。 举个例子,看看我的 javascript 客户端解决方案。 这也可以在Node.js进行少量工作,您只需更改在块函数ExecutionBlock请求的方式即可。

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

在以下代码段中尝试一下。

要了解如何将此解决方案应用于Node.js在此处查看我对http get 和 post 的实现,并在本文后面查看异步任务节点中更复杂的执行。

 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" />

对于通过PromisePromise.all应用于 node.js 的类似方法,请参阅我的问题here 这是关于以异步方式在节点中生成通用进程的执行。

这里有一个更复杂的例子展示了如何使用PromiseN * M http.get执行器中生成和链接多个级别的 http 调用执行。 因此,您将开始执行N请求,每个请求将启动M请求,感谢Promise.all您将等待每个请求,等待第一个M所有结果,然后是N * M个请求响应数组的所有结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM