处理多个异步回调函数的调用

3

我正在使用 learnyounode 学习 node.js。 在 JUGGLING ASYNC 中遇到了问题。 问题如下:
你会从命令行参数中得到三个 URL 地址,需要使用 http.get() 调用获取这些地址的数据,并按照它们在参数列表中的顺序打印出来。 以下是我的代码:

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

这是我不明白的问题:我试图使用字典存储使用response.on('end', function(){})为每个url完成的数据。然而,我不知道如何获取那个http.get()的url。如果我可以在http.get()内部做一个局部变量,那就太好了,但我认为无论何时声明一个变量为var url,它都将始终指向最后一个url。由于它是全局的并且通过循环不断更新。对于我存储这些已完成数据作为键等于url的值的最佳方法是什么?
3个回答

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按顺序访问每个响应时,您的开销将大大增加。我不建议这样做。


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

0

立即调用函数表达式(IIFE)可能是您问题的解决方案。它允许我们将特定值绑定到函数,例如您的情况下获取响应的URL。在下面的代码中,我将变量i绑定到index,因此无论哪个URL获取响应,打印列表的该索引都将被更新。有关更多信息,请参阅此网站

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接