【问题标题】:node.js multiple asynchronous functionsnode.js 多个异步函数
【发布时间】:2017-11-24 04:39:25
【问题描述】:
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 中收集数据作为字符串,并按照它们在命令行中出现的顺序将它们打印到控制台。现在代码没有打印任何东西,它陷入了无限循环。怎么了?

【问题讨论】:

    标签: javascript node.js asynchronous


    【解决方案1】:

    代码中有两个问题。首先,您有一个循环变量的闭包,这使得该值与您预期的不同,正如 guvinder372 所解释的那样。另请参阅 this answer 讨论该问题和 this 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]);
               });
       });
    }
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        您不能在不等待响应的情况下在for...loop 循环中执行多个 http 请求。 要以现代方式编写此代码,您需要一些新的构造/模式,例如Promise。然后,您可以等待每个响应、收集响应并退出到调用者。 举个例子,看看我的 javascript 客户端解决方案。这在Node.js 中也可以使用,您只需更改在块函数ExecutionBlock 中执行请求的方式。

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

        在下面的 sn-p 中尝试一下。

        要了解如何将此解决方案应用于Node.js,请参阅我的http 实现并发布here,并在本文后面查看异步任务节点中更复杂的执行。

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-02
          • 2019-01-20
          • 1970-01-01
          • 2014-08-16
          • 2019-07-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多