2015-10-17 70 views
1

我正在解決問題10:ASYNC JUGGLING中的learnyounode教程。爲什麼要計算回調?

此問題與您需要使用http.get()的 之前的問題(HTTP COLLECT)相同。不過,這次你會得到 作爲前三個命令行參數提供的三個URL。

您必須收集每個 URL提供給您的完整內容並將其打印到控制檯(stdout)。您不需要打印出長度爲 的數據,只需將數據打印爲字符串;每個URL一行。該捕獲是 ,您必須以與作爲命令行參數提供給您的URL爲相同的順序將它們打印出來。

官方的解決方案涉及計數回調:

var http = require('http') 
var bl = require('bl') 
var results = [] 
var count = 0 

function printResults() { 
    for (var i = 0; i < 3; i++) 
    console.log(results[i]) 
} 

function httpGet (index) { 
    http.get(process.argv[2 + index], function (response) { 
    response.pipe(bl(function (err, data) { 
     if (err) 
     return console.error(err) 

     results[index] = data.toString() 
     count++ 

     if (count == 3) // yay! we are the last one! 
     printResults() 
    })) 
    }) 
} 

for (var i = 0; i < 3; i++) 
httpGet(i) 

程序必須等待,直到所有三個響應都打印出來之前被接收,所以他們在他們輸入了相同的順序出來。

我試圖參與使用回調,以確保正確的順序:

var http = require('http') 
var bl = require('bl') 
var results = [] 

function printResults() { 
    console.log(results[0]) 
    console.log(results[1]) 
    console.log(results[2]) 
} 

function httpGet (i) { 
    http.get(process.argv[2 + i], function (response) { 
    response.pipe(bl(function (err, data) { 
     if (err) 
     return console.error(err) 
     results[index] = data.toString() 
    })) 
    }) 
} 

function httpGetAll (callback) { 
    httpGet(0) 
    httpGet(1) 
    httpGet(2) 
    callback() 
} 

httpGetAll(printResults) 

但這吐出undefined三次。所以看起來好像printResults()在三個httpGet()行被執行之前被調用。似乎我不明白回調以及我的想法。

所以我的問題是,有什麼辦法可以實現這個使用httpGetAll()回調?或者我來計算回撥到httpGet()

+1

你必須數,否則使用承諾。 'http.get()'調用是**異步**。它們在HTTP請求實際完成之前立即返回。然後傳遞給'http.get()'的回調將與響應一起被調用。 – Pointy

回答

1

但是這個吐出三次未定義。所以看起來printResults()在三個httpGet()行被執行之前被調用。似乎我不明白回調以及我的想法。

是的,你誤解了異步代碼的行爲。這三個httpGet() ARE被首先執行,但它們的結果的異步回調不會被執行,直到稍後的事件循環打勾。如果您查看httpGet,縮進1級的代碼在第一個tick上運行,這只是第一行,嵌套回調函數中縮進2級的所有代碼都不會在同一個tick上執行。該代碼僅在HTTP響應到達後的事件隊列中進行調度,但節點不會等待,而是繼續進行。

所以我的問題是,有什麼辦法可以實現這個使用httpGetAll()回調?或者我必須計算回調到httpGet()?

是的,有些方法可以在沒有專門計算回調的情況下正確實現,但是,您必須以某種方式「跟蹤」掛起的呼叫。計數是一種簡單而有效的方法,但您也可以使用數組作爲掛起的調用隊列,當每個響應到達時從隊列中移除一個元素,並在隊列爲空時知道您已完成。您也可以在done屬性中啓用false,並在響應到達時將其設置爲true,然後通過確保所有done屬性均爲true來檢查它們是否全部完成,從而爲每個請求跟蹤對象的狀態。這在技術上並不算數,但它是類似性質的簿記。