2011-12-23 126 views
4

我們知道JavaScript是單線程的,但我們想確認我們對JavaScript中異步事件處理的理解。更重要的是,我們想確認我們沒有接觸到潛在的競爭條件。JavaScript事件處理的競爭條件?

從概念上講,我們的移動應用程序的工作原理是這樣的:

  1. 我們在加載移動網頁調用函數foo

  2. 截至foo最後,我們使用setTimeout再次調用foo(以一秒的延遲)如果計數器大於0更大。如果計數器遇到0,我們將加載一個新頁面。超時保存在一個變量中。

  3. 如果點擊一個按鈕,我們調用函數do_tap並清除步驟二中保存的超時變量(並執行其他操作)。

do_tapfoo更新都在同一個頁面元素,我們想確認,他們不會互相步驟。

問題:

  1. 假設的foo的執行期間發生的抽頭。在foo完成後,瀏覽器隊列do_tap是否會開始執行?換句話說,我們保證一旦foo開始,我們永遠不會看到執行foodo_tap交錯?

  2. 如果水龍頭先出現怎麼辦? do_tap保證在foo開始前完成,對吧?

+0

由於執行是單線程的,因此'foo'在'Do_tap'返回之前開始執行是根本不可能的(反之亦然)。閱讀本文,您將瞭解瀏覽器中的執行隊列是如何工作的:http://ejohn.org/blog/how-javascript-timers-work/ – 2011-12-23 00:35:56

回答

6

除了網絡工作者和合作框架或窗口(這裏沒有使用),Javascript在給定窗口內是單線程的,因此在該窗口中不會有兩個執行線程同時運行。因此,使用線程時,您不必擔心可能成爲典型擔心的競爭條件。

在封面下,Javascript有一個事件隊列。您當前的執行線程將運行至完成,然後當完成時,JavaScript解釋器將檢查事件隊列以查看是否有更多事情要做。如果是這樣,它會觸發該事件並啓動另一個執行線程。幾乎所有的事情都經歷了事件隊列(定時器,重要事件,調整大小事件,鼠標事件等)。

您可以閱讀更多關於它的信息,並在my other answers的其中一個相關參考資料中查看該主題。

+1

這幾乎是正確的,除了框架具有獨立的執行上下文,並且如果它們都訪問相同的數據,如'top.myVariable',則可能有競爭條件。查看http://dev.opera.com/articles/view/timing-and-synchronization-in-javascript/並在該頁面搜索競賽 – 2013-09-16 22:32:41

+0

@JuanMendes - 好點。我會更新我的答案。 – jfriend00 2013-09-17 06:20:23

4

事件執行進行到單線程,直到事件已被處理。直到那個時候,沒有其他事件循環將被啓動。

換句話說,當某個事件處理程序正在運行時,任何其他事件的其他處理程序都不會中斷它。

因此,問題1和問題2的答案都是「是」。 (當然,這是禁止瀏覽器錯誤的,但是如果考慮到這一點,你就不可能走得太遠,這不像是有任何同步原語可以回退,我只是說這是因爲有一段時間在此期間,Safari可以在運行另一個「DOMready」事件處理程序的過程中觸發「DOMready」事件。但是,這很明顯是一個錯誤。)

+0

謝謝,我們只是想確認! do_tap()和foo()都更新相同的頁面元素,我們希望確保它們不能互相踩在一起。再次感謝您的肯定。 – Crashalot 2011-12-23 00:27:26

0

只要do_tap()所做的第一件事就是clearTimeout在執行Do_tap()期間,foo將無法運行。但是,如果在foo()這樣的數據庫請求中啓動了一個異步進程,那麼當foo()完成其請求時,可能會在Do_tap()中訪問數據庫,如果foo()具有可以理論上在Do_tap()完成執行後調用。

0

我沒有聽到任何其他人這樣說,但我認爲#2的答案是不同的瀏覽器實現能夠並且確實以微妙的方式區分哪些排隊事件是首先處理的。不,不存在交錯的可能性,但是setTimeout(func,0)或鼠標事件是否先被處理不受語言規範的保證,並且在實踐中可能很重要。而setTimeout(func,100)保證在當前處理的事件期間接收到的待處理事件之後處理。

只是說。