2011-07-12 65 views

回答

56

假設,然後,其他一些JavaScript方法稱爲myFunction被調用我的頁面上時myCallback是異步調用。

一個操作優先於另一個嗎?他們是否都在同一時間運行?怎麼了?

瀏覽器上的JavaScript是單線程的(禁止使用web workers,而且語法明確)。所以myFunction將運行,直到它返回  —與某些注意事項(繼續閱讀)。如果ajax層完成操作myFunction正在運行(它很可能)並且需要調用該回調,則該呼叫獲得排隊。下一次您的代碼產生時,隊列中的下一個呼叫將被觸發。

因此,看起來我們從不必擔心競賽狀況。大多數情況都是如此,但有些微妙之處。例如,考慮下面的代碼:

var img = document.createElement('img'); 
img.src = /* ...the URL of the image... */; 
img.onload = function() { 
    // Handle the fact the image loaded 
    foo(); 
}; 
doSomethingElse(); 
doYetAnotherThing(); 

由於JavaScript的瀏覽器上是單線程的,我保證讓load事件時加載圖像,對不對?

錯誤。

JavaScript代碼是單線程的,但其餘的環境可能不是。因此,它可以發生,將其具有的img.src,瀏覽器可能會看到它有它可以使用圖像的緩存副本,所以它觸發的img之間的img.src = ...線和img.onload = ...load事件。由於我的處理程序尚未附加,因此我無法接聽電話,因爲當我附加了處理程序時,該事件已經被解僱。

但是你可以看到排隊的效果,如果我們扭轉這些行:設置src

var img = document.createElement('img'); 
img.onload = function() { 
    // Handle the fact the image loaded 
    foo(); 
}; 
img.src = /* ...the URL of the image... */; 
doSomethingElse(); 
doYetAnotherThing(); 

現在我掛鉤事件。如果img.src = ...線和doSomethingElse線(因爲瀏覽器在高速緩存中的圖像)之間的事件觸發,回調到我的處理程序獲取排隊doSomethingElsedoYetAnotherThing在我的處理程序執行之前運行。只有當控制通過我的代碼時,排隊調用我的處理程序才能最終運行。 JavaScript代碼是單線程的,但環境不是。

您也可以以非明顯的方式屈服於主機環境。例如,通過調用alert或其breathren confirmprompt等,這些功能的堅持像瘡大拇指,他們是現代的JavaScript,因爲他們不是事件驅動;相反,在顯示模式窗口時JavaScript執行被暫停。但是bobincehis in-depth discussion here中指出,這並不意味着當模式顯示時,其他代碼都不會運行。它仍然是單線程的,但是一個線程被暫停在一個地方(通過模式),​​並用於在其他地方運行代碼;確實是非常好的區分。 (鮑勃也指出了一些事件處理  —他focus例如  —這似乎打破了這一規則,但它沒有他的榜樣調用focus,進而調用事件處理程序,然後返回。沒什麼兩樣)Bob指出的項目的關鍵在於,您的代碼在主機環境中調用了一些東西,它會消失並執行某些操作(顯示模式對話框,觸發blurfocus處理程序,等等。)。

alert及其在特定的原因breathren種種污穢的,特別是圍繞focusblur,我建議避免他們贊成更現代的技術(也可看約18倍更好)。)

所以這些是答案一開始提到的警告。尤其如果myFunction電話alert,至少在Firefox中的AJAX完成回調得到alert期間(不是大多數其他瀏覽器它會)上運行。如果你很好奇嘗試什麼呢,並在alerts和這樣的,here's a test page測試setTimeout和Ajax不會發生;你可以擴大測試的範圍。

+0

我有一種感覺,瀏覽器在內部對這種行爲使用一個eventloop(如node.js)。如果是這種情況,你可能想談談如何eventloops工作。 – Raynos

0

ajax調用與同時。所以當ajax調用成功時,調用回調函數,然後調用myfunction。

+1

雖然大多數情況是正確的,但不幸的是,這個誤解了這個問題:'myFunction'完全獨立於回調,並且不被調用回電話。 – ninjagecko

0

您可以快速測試此警報('第一個');警報('第二個');在這兩個函數中,看看哪個模式彈出窗口首先出現。如果你的代碼真的受到這個命令的影響,那麼在兩者中加入一些條件檢查來防止/允許一些東西。原生js的速度與往返於服務器的完整往返速度是截然不同的。除非你有一些javascript在無限循環中運行,否則在其他函數執行期間返回的ajax調用的機率很小。

2

AJAX回調在下一個事件循環中運行。

+1

提及事件循環的+1。許多人不明白系統是如何運作的。也許你可以包含一個鏈接,解釋JavaScript的evented-ness? – tjameson

3

Javascript類單線程見Is JavaScript guaranteed to be single-threaded?。所以答案是NO,你的事件處理程序和你的函數可以同時運行,或者它們可能不運行。

+1

雖然這是一些實現技術上是可行的,程序員應該總是假設一個事件觸發模型嚴格遵守。除此之外的任何事情都會導致瘋狂。 – tjameson

-1

當ajax成功並調用myCallback時,它將同步運行。所以myCallback就像其他函數一樣,你先調用它會先運行,或者你最後調用它最後運行。他們不會在同一時間運行。

+0

同步是一個有很多奇怪內涵的恐怖詞彙。也許這可以解釋得更好一點?就像提到隊列中的事件是如何依次執行的一樣。 – tjameson

+0

@tjameson - 我們在一個特定的主題,我想我可以使用同步。 :)雖然我解釋了,謝謝! – dpp

+0

你投了棄權,那麼這有什麼問題呢? – dpp

7

這些答案都是錯誤的[編輯:這個答案被張貼時,至少有3-4錯]。 XHR事件放入事件隊列/池中。當單線程JavaScript線程不忙時,它將從事件池中獲取下一個事件,並對其執行操作。其中一個事件是你的XHR「AJAX」請求,它將觸發回調,然後執行。這就是所有沒有中斷的事件驅動系統的工作原理。

編輯:Upvoting喬的答案,鏈接到Is JavaScript guaranteed to be single-threaded?,並提到了微妙的邊緣的情況下。非常豐富。

+0

他們真的*全部*錯了嗎? – icktoofay

+0

我同意。並非所有都是錯誤的,但很多都是誤導。 @icktoofay,你的回答絕對正確,所以我+你的答案。 Ninjagecko的答案只是更強大一點。 – tjameson

0

AJAX調用是「asyncronous」,這意味着「火了一個電話,讓我知道你想讓我回電話時,即時通訊做了什麼」。

總之

這樣:

function DoSomething() { AJAXCall(Callback); } 

... some time passes then ... 

function Callback() { Done(); } 

這些2函數調用之間什麼都可能發生,回調仍然會被調用時響應返回因爲雖然JavaScript運行是單線程的瀏覽器將棧調用發生按照某種順序(可能是他們的訂單,但沒有保證)。

這是一個恥辱,我只是做拉住我的舊網站,因爲我有做負載幾個ajax調用頁面的經典例子,因爲每個電話回來,將填充頁面的各個部分。

儘管每次調用都「附加」到文檔加載事件,但一次只能進行1次調用,但服務器可以以任何順序響應任何調用,因爲服務器可能是多線程的(可能是)。

認爲JavaScript是一個虛擬框,瀏覽器可以在其中傳遞一小塊代碼,它一次只能運行一次,但它可以按照它認爲合適的順序運行很多腳本(通常這個多個Ajax調用是不可預知的,因爲誰知道服務器何時可能會返回結果)

相關問題