2014-09-11 64 views
1

我們假設我們有一個功能foo(item, callback)和一個集合items如何處理異步函數和集合?

我想要做的是將items中的每一項替換爲執行foo所返回的值,就像Array.map()一樣。

但問題在於:foo的結果在回調中產生,因此我無法在回調本身之外訪問它(顯然,我無法更改foo以滿足我的需要)。

你可以嘗試像

var results = []; 
items.map((function(el) { 
    foo(el, function(result) {results.push(time)}); 
}); 

的做法,但那麼你可以不知道什麼時候你results收藏將是「準備好了」。

我完全無能爲力。 我該怎麼辦?什麼是模式?

編輯:我更感興趣的是香草JavaScript的方式來實現這個比工具/庫,這是無論如何可以接受的答案。

+0

提供的示例不是異步的。 items.map完成後腳本的執行將繼續,items.map完成後,您的結果變量將立即「準備就緒」。 – Tiborg 2014-09-11 12:54:10

+0

爲什麼?可以隨時執行'foo'函數的回調。 – mattecapu 2014-09-11 12:55:56

+0

包裝你的代碼功能和使用回調.... – Ravi 2014-09-11 12:57:22

回答

2

在香草JS我會做這樣的:

var items = ['item 1', 'item 2', 'item 3'] 

function foo(item, callback) { 
    // this is provided just to test the async nature of your callback 
    setTimeout(function() { 
     callback.call(null, item + ' async') 
    }, Math.random() * 5000); 
} 


var results = []; 
var count = 0; 
items.forEach(function (element, index, array) { 
    foo(element, function (result) { 
     results[index] = result; 

     // the actual "ready" check 
     if (++count == items.length) { 
      // here you should notify your code that all items have been replaced 

      // after a random number of seconds between 1 and 5 in the current example, it should 
      // write ['item 1 async', 'item 2 async', 'item 3 async'] 
      console.log(results); 
     } 
    }) 
}); 

我不知道這是否是一個模式或者最好的方式,但我認爲是簡單,快捷。請注意,forEach僅適用於IE9 +。對於IE < 9,你可以使用jQuery。或者手動編寫for循環(但要小心閉包和索引)。

2

使用async庫時,這變得非常簡單。

async.each(items, function(el, callback) { 
    foo(el, function(result) { 
     callback(result); 
    }); 
}, function(results) { 
    doSomethingWith(results); //results being an array of the callbacked results. 
}); 
+0

謝謝你的回答!這實際上是一個偉大的圖書館。但你能解釋它是如何工作的嗎?我試圖看看'async.each'的源代碼,但我不明白髮生了什麼,我認爲是因爲整個代碼有點怪異。 – mattecapu 2014-09-11 13:06:56

+2

這不是哈克。它會統計收集中的項目,並在收到回調時增加一個數字。如果增加的數字與項目計數相同,則會返回結果。 – 2014-09-11 13:16:40

+0

哦,我懷疑它,非常聰明,但它對我來說聽起來仍然很不好 – mattecapu 2014-09-11 13:29:54