2013-12-24 273 views
3

我在学习node.js与learnyounode。 我遇到问题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) 
      }) 
      } 
    }) 
    }) 
} 

这里是我不理解的问题: 我试图完成的数据存储在response.on('end', function(){})使用字典的每个URL。但是,我不知道如何获得该http.get()的网址。如果我可以在http.get()内部做一个局部变量,那会很好,但我认为每当我声明一个变量为var url时,它总是会指向最后一个url。由于它是全球性的,它通过循环不断更新。对于我来说,将这些已完成的数据存储为键值与键值相等的最佳方式是什么?

回答

13

这就是我将如何去解决这个问题。

#!/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回调闭包中定义一个变量并使用它来存储这些urls,这样你不会以最后一个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,因此,无论哪个网址获得响应,打印列表的索引都将被更新。欲了解更多信息,请参阅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) 
}