2013-12-24 266 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) 
}