2008-09-24 238 views
87

我已看過此鏈接:Implementing Mutual Exclusion in JavaScript。 另一方面,我已經閱讀了JavaScript中沒有線程,但究竟是什麼意思?JavaScript中是否需要互斥體?

當事件發生時,代碼中哪裏可以中斷?

如果JS中沒有線程,我是否需要在JS中使用互斥鎖?

具體而言,我想知道使用函數setTimeout()XmlHttpRequestonreadystatechange對全局訪問變量的影響。

+1

不,沒有互斥或JavaScript的任何其他併發控制工具。請參閱[爲什麼沒有JavaScript中的併發控制工具](http://uzairfarooq.github.io/why-no-concurrency-control-tool-in-javascript/)。 – 2015-07-17 08:06:19

回答

87

JavaScript是定義爲折返語言,這意味着有沒有線程暴露給用戶,實現中可能有線程。像setTimeout()和異步回調函數需要等待腳本引擎在能夠運行之前進入睡眠狀態。

這意味着在處理下一個事件之前,事件中發生的所有事情都必須完成。

這就是說,如果你的代碼做了一些事情,那麼當異步事件被觸發和回調被調用時,它的值就不會改變。

例如,如果您有一個數據結構,您可以在其中單擊一個按鈕併發送調用回調的XmlHttpRequest,以破壞性方式更改數據結構,並且您有另一個按鈕可以直接更改同一數據結構當事件被觸發並且執行回調時,用戶可能在回調之前點擊並更新數據結構,然後可能丟失該值。

雖然您可以創建這樣的競爭條件,但由於每個函數都是原子的,因此很容易防止在您的代碼中出現這種情況。事實上,這將是很多工作,並採取一些奇怪的編碼模式來創造競爭條件。

+1

創建這種競爭條件並不難:例如,我在字段中有一個「onkeyup」事件,它會觸發對數據庫的ajax調用以獲取一些值。快速輸入數據很容易導致亂序結果。 – thomasb 2017-11-17 16:15:11

5

JavaScript是單線程的......雖然Chrome可能是一個新的野獸(我認爲它也是單線程的,但每個標籤都有它自己的JavaScript線程......我沒有仔細研究它,所以不要在那裏引用我的話)。

但是,您需要擔心的一件事是您的JavaScript如何處理多個Ajax請求,它們的傳遞順序與您發送的順序不同。所以,你真正需要擔心的是確保你的Ajax調用的處理方式,如果結果以不同於你發送的順序返回,他們將不會踩到對方的腳上。

這同樣適用於超時太...

JavaScript時長多線程,那麼也許擔心互斥等....

1

事件發出信號,但JavaScript執行仍然是單線程的。

我的理解是,當事件發出信號時,引擎會停止正在執行的事件,以運行事件處理程序。處理程序完成後,腳本執行恢復。如果事件處理程序更改了某些共享變量,則恢復代碼將會看到這些「出乎意料」的變化。

如果你想「保護」共享數據,簡單的布爾標誌應該就足夠了。

1

JavaScript中,語言,可以爲多線程的,只要你想,但JavaScript引擎的瀏覽器的嵌入一次只運行一個回調(的onload,聚焦狀態,<腳本>,等...)(每片,據推測)。威廉關於在註冊和接收回調之間使用Mutex的建議不應該因爲這個原因而被過分地使用,因爲你不想在中間回調中阻塞,因爲解鎖它的回調將被阻止在當前回調之後! (哇,英語很討厭線程的問題。)在這種情況下,如果設置了標誌,可能需要按照重新分派當前事件的方式執行某些操作,無論是字面上的還是setTimeout()之類的。

如果您使用的是JS的不同嵌入方式,並且一次執行多個線程,它可能會變得更加冒險,但由於JS可以輕鬆使用回調並將對象鎖定在屬性訪問上,顯式鎖定是幾乎沒有必要。但是,如果爲使用多線程的通用代碼(例如遊戲腳本)設計的嵌入也沒有給出一些明確的鎖定原語,我會感到驚訝。

對不起,對文本的牆!

15

這個問題的答案有點過時,雖然在給定的時候是正確的。如果查看不使用webworkers的客戶端JavaScript應用程序,仍然正確。

文章在網絡工作人員:
multithreading in javascript using webworkers
Mozilla on webworkers

這清楚地表明,通過網絡工作人員的JavaScript具有多線程功能。至於這個問題是JavaScript中需要互斥體?我不確定這一點。但這個計算器後,似乎相關:
Mutual Exclusion for N Asynchronous Threads

+2

從過去爆炸,但當多個標籤訪問相同的本地存儲時,我遇到了互斥鎖的需要 – psp 2014-05-15 13:46:10

+1

Web工作人員不會影響重入,因爲它們不共享變量狀態,只通過傳遞消息來與主線程通信,這會觸發事件。 – Alnitak 2014-08-01 11:05:00

9

由於@william指出,

如果你的代碼做了它需要一個 值不是當異步事件之間改變,你可能需要一個互斥被調用時被觸發並且 。

這可以進一步推廣 - 如果你的代碼做了一些事情,它期望在異步請求解決之前對資源進行排他控制,那麼你可能需要一個互斥鎖。

一個簡單的例子是你有一個按鈕,觸發一個Ajax調用在後端創建一個記錄。您可能需要一些代碼來保護您免於觸發快樂用戶點擊並創建多個記錄。有很多方法可以解決這個問題(例如,禁用按鈕,啓用Ajax成功)。你也可以使用一個簡單的鎖:

var save_lock = false; 
$('#save_button').click(function(){ 
    if(!save_lock){ 
     //lock 
     save_lock=true; 
     $.ajax({ 
      success:function() 
       //unlock 
       save_lock = false; 
      } 
     }); 
    } 
} 

我不知道這是最好的方法,我很想看看別人是如何處理JavaScript的相互排斥,但據我所知,這是一個簡單的互斥和它很方便。

1

是的,當訪問在標籤頁/窗口之間共享的資源時,Javascript中可能需要互斥鎖,例如localStorage

例如,如果用戶有兩個選項卡中打開,像下面這個簡單的代碼是不安全的:

function appendToList(item) { 
    var list = localStorage["myKey"]; 
    if (list) { 
     list += "," + item; 
    } 
    else { 
     list = item; 
    } 
    localStorage["myKey"] = list; 
} 

的localStorage的項目是「得到」和「設置」之間的時間裏,另一個標籤可以有修改了這個值。這通常不太可能,但可能 - 您需要自己判斷在特定情況下與任何爭用相關的可能性和風險。

見一個更詳細的在下面的文章: