node.js多个异步函数

时间:2016-05-06 05:55:26

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

3 个答案:

答案 0 :(得分:2)

代码中存在两个问题。首先,你有一个循环变量的闭包,它使得值与你期望的guvinder372解释的不同。另请参阅讨论问题的this answerthis answer,它们演示了使用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]);
           });
   });
}

答案 1 :(得分:0)

问题 - 当调用回调处理程序时,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]);
           });
   });
}

答案 2 :(得分:0)

您无法在for...loop周期内执行多个http请求,而无需等待响应。 要以现代方式编写此代码,您需要一些新的构造/模式,例如Promise。然后,您可以等待每个响应,收集响应并退出呼叫者。 举个例子,看看我的javascript客户端解决方案。这也适用于Node.js中的一小部分工作,您只需更改块函数ExecutionBlock中执行请求的方式。

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

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

要了解如何将此解决方案应用于Node.js,请参阅http获取和发布here的实现,并在本文后面看到,以便在异步任务的节点中执行更复杂的操作。 / p>

&#13;
&#13;
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) });
&#13;
<div id="console" />
&#13;
&#13;
&#13;

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

更复杂的示例here显示了如何使用N * Mhttp.get Promise执行程序中生成和链接多个级别的http调用。因此,您将执行N个请求,每个请求都会启动M个请求,并且感谢Promise.all您将等待每个请求,等待第一个M的所有结果然后是N * M请求响应数组的所有结果。