2013-07-19 99 views
2

我想寫一個函數,該函數需要回調並在函數完成後調用它。不阻止的回調函數

這很簡單:

var callback = function (ref) { 
    var i = 1337; 
    while (i--) { 
     console.log(ref, 'callback'); 
    } 
}; 

var someFoo = function (ref, callback) { 
    console.log(ref, 'self'); 

    callback(ref); 
} 

someFoo('one', callback); // 1 
someFoo('two', callback); // 2 

但在這裏,我面臨這個問題:直到allback完成首先someFoo調用塊。這意味着這個代碼相當於這個(它阻塞,直到每個功能完成):

someFoo('one'); 
callback('one'); 
someFoo('two'); 
callback('two'); 

現在的問題:如何使回調調用異步?

回答

9

變化:

callback(ref); 

要:

setTimeout(function(){ callback(ref); }, 0); 

或者,因爲你正在編寫一個Chrome擴展,並且,因此,不必擔心舊的瀏覽器,你可以使用bind

setTimeout(callback.bind(null, ref), 0); 
+0

這看起來像骯髒的黑客。還有一些「官方」方式嗎? –

+3

@WaleryStrauch沒有,唯一的其他方法會更骯髒。 – Paulpro

+1

這不是一個骯髒的黑客。正如Mike Thompson所回答的那樣,JavaScript代碼是同步的。 「異步」執行的唯一來源是外部影響(例如,瀏覽器響應事件或定時器) – Sacho

2

在瀏覽器中實現的JavaScript是單線程的,所以你不能做一個rea l異步調用。你可以做的就是這樣的事情來近似地認爲:

setTimeout(function() { 
    callback(ref); 
}, 1000); 

其中1000是在毫秒1秒(根據需要進一步延遲)。但是,由於它是單線程的,回調會阻止其他正在運行的代碼。

新瀏覽器支持web workers,但使用網絡工作人員來近似線程會讓您看到許多舊版瀏覽器無法使用的代碼,即使現在也不是所有新瀏覽器都支持完整的規範。

+0

我的情況是Chrome擴展,所以我不在乎IE瀏覽器(或舊瀏覽器) –

+0

我不認爲你選擇的答案確實對你有幫助,因爲它所做的只是在同一個線程的特定時間任意執行一段代碼。你可能只需要咬緊牙關,不斷調整,直到找到更快速運行的更明顯同步的東西。 –

+0

@MikeThomsen'setTimeout'確保回調在當前執行流程完成後的某個時間執行。這就是Javascript事件循環的工作原理。它不是任意的,它不會阻塞任何正在運行的其他代碼,因爲只有當其他代碼(已經啓動)完成時纔會運行。 – Paulpro