2011-07-27 130 views
3

如果我的影片通過這個函數的函數:(可以有任意數量的work電話與任意數量的在其中)確定異步操作結束的javascript

function(work) { 
    work(10); 
    work(20); 
    work(30); 
} 

work一些性能異步活動 - 例如,對於這個例子,它只是一個timeout。我完全可以控制work在完成此操作時所做的事情(實際上,它的定義一般而言)。

確定何時完成所有對work的呼叫的最佳方式是什麼?


我現在的方法增加一個當工作被稱爲計數器,它完成時減一,並觸發all work done事件當計數器爲0(這是每一個遞減後檢查)。不過,我擔心這可能是某種競爭條件。如果情況並非如此,請證明我的原因,那將是一個很好的答案。

+0

這是值得考慮的,至少原則:HTTP://www.benjiegillam。com/2011/11/multiple-asynchronous-callbacks/ –

回答

2

有一噸的你可以這樣寫程序的方式,但你的使用計數器會工作得很好的簡單的技術。

重要的是要記住,這將起作用的原因,是因爲Javascript在單線程執行。所有瀏覽器和node.js AFAIK都是如此。

基於下面的深思熟慮的意見,該解決方案工作,因爲該JS事件循環將在像的順序執行功能:

  1. 功能(工作)
  2. 工作(10)
  3. 計數器++
  4. 開始異步函數
  5. 工作(20)
  6. 計數器++
  7. 啓動異步功能
  8. 工作(30)
  9. 計數器++
  10. 啓動異步功能
  11. - 回給事件循環 -
  12. 異步函數完成
  13. counter--
  14. - 退出事件循環 -
  15. 異步功能完成
  16. counter--
  17. - 回給事件循環 -
  18. 異步函數完成
  19. counter--
  20. 計數器爲0,這樣你就解僱你的工作做消息
  21. - 回給事件循環 -
+0

爲什麼單線程意味着這會起作用?多線程環境中的計數器有什麼問題? – davin

+0

@davin計數器在所有工作完成之前可能會擊中'0'的局部最小值。即doWork(1),doWork(2),<都完成,計數器爲0 fire回調> doWork(3) – Raynos

+0

如果多線程訪問您的計數器,則必須保證自動更新計數器。在某些語言中,i ++或i--不能保證是原子的,因爲操作涉及讀取變量並設置它。這使得它在多線程環境中受到線程調度程序的支配。根據您的使用情況,可能需要考慮多個線程同時運行的其他問題 - 比如一個@Raynos指出的問題。 – Mike

2

沒有比賽條件。每個請求在完成時都要求執行遞減操作(總是有,包括http故障,這很容易忘記)。但是,可以通過包裝你的呼叫以更封裝的方式處理。

未經檢驗的,但是這是要點(我實現了一個對象,而不是一個計數器,所以理論上可以延長這有關於具體要求更精細的查詢):

​​

用法:

而不是$.post("url", ... function(){ /*success*/ } ...);我們會做

var requestId; 
requestId = ajaxWrapper.makeRequest("url", ... 
    function(){ /*success*/ ajaxWrapper.finishRequest(requestId); } ...); 

如果你想成爲更復雜,你可以調用添加到finishRequest你自己的包裝裏面,這樣的用法是幾乎完全透明的:

ajaxWrapper.makeRequest("url", ... function(){ /*success*/ } ...); 
1

我有一個after效用函數。

var after = function _after(count, f) { 
    var c = 0, results = []; 
    return function _callback() { 
    switch (arguments.length) { 
     case 0: results.push(null); break; 
     case 1: results.push(arguments[0]); break; 
     default: results.push(Array.prototype.slice.call(arguments)); break; 
    } 
    if (++c === count) { 
     f.apply(this, results); 
    } 
    }; 
}; 

下面的代碼只是工作。因爲JavaScript是單線程的。

function doWork(work) { 
    work(10); 
    work(20); 
    work(30); 
} 

WorkHandler(doWork); 

function WorkHandler(cb) { 
    var counter = 0, 
     finish; 
    cb(function _work(item) { 
    counter++; 
    // somethingAsync calls `finish` when it's finished 
    somethingAsync(item, function _cb() { 
     finish() 
    }); 
    }); 
    finish = after(counter, function() { 
    console.log('work finished'); 
    }); 
}; 

我想我應該解釋一下。

我們傳遞的是不工作的workhandler功能。

工作處理程序調用它並傳遞工作。

,做工作電話工作多次遞增計數器

自認爲做的工作函數的功能是不是異步的(非常重要)完成任務後,我們可以定義完成的功能。

正被工作的當前同步塊(其全部workhandler的執行)之前進行不能完成(並調用未定義光潔度功能)asynchronouswork已完成。

這意味着整個workhandler結束後(且變量完成設置)的異步工作職位將開始結束,並呼籲結束。只有他們所有的人都打完了,回調纔會發送到after火。