处理多个调用异步回调

时间:2013-12-24 03:15:14

标签: javascript node.js asynchronous

我正在使用learnyounode学习node.js。 我遇到了JUGGLING ASYNC的问题。 问题描述如下:
您将获得三个URL作为命令行参数。您应该进行http.get()调用以从这些URL中获取数据,然后按照与参数列表中的顺序相同的顺序打印它们。 这是我的代码:

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

以下是我不明白的问题: 我正在尝试使用字典将完成的数据存储在每个URL的response.on('end', function(){})中。但是,我不知道如何获取http.get()的网址。如果我可以在http.get()中做一个局部变量,那就太棒了但我想每当我将变量声明为var url时,它总是指向最后一个url。因为它是全局的并且它通过循环不断更新。我将这些已完成数据存储为密钥等于url的值的最佳方法是什么?

3 个答案:

答案 0 :(得分:12)

这就是解决问题的方法。

#!/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]));

它在每个请求开始时将请求添加到数组中,这样一旦完成,我可以很好地遍历响应,知道它们的顺序正确。

在处理异步处理时,我发现将每个进程视为具体的开始和结束更容易。如果您需要保留请求的顺序,则必须在创建每个进程时进行输入,然后在完成时返回该记录。只有这样才能保证你的东西顺序正确。

如果你急于使用上面的方法,那么你可以在你的get回调闭包中定义一个变量并使用它来存储url,这样你就不会最后一个url覆盖你的变量了。但是,如果你这样做,当你必须使用process.argv中的url来按顺序访问每个响应时,你将大大增加你的开销。我不建议。

答案 1 :(得分:0)

我对这一挑战的看法略有不同。我正在创建一个调用http.get的函数数组,并立即使用它们的特定上下文调用它们。流写入对象,其中密钥是与该流相关的服务器的端口。当触发结束事件时,它会将该服务器添加到已完成的数组中 - 当该数组已满时,它会按服务器的原始顺序进行迭代并回显。

没有正确的方法,但可能有十几种方式。想和我分享。

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

答案 2 :(得分:0)

立即调用函数表达式(IIFE)可以解决您的问题。它允许我们绑定函数一个特定的值,在你的情况下,获取响应的url。在下面的代码中,我将变量i绑定到index,因此,无论哪个url获得响应,都将更新打印列表的索引。有关更多信息,请参阅this website

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