2014-09-05 40 views
1

我使用AngularJS創建一個web表單。此表單包含三個按鈕,當點擊時,按三種不同的方式對無序列表中的列表項進行排序。在滯後峯值期間,我觀察到一些奇怪的行爲,而在第一個方法調用仍在運行時單擊這3個按鈕中的另一個會導致爭用條件混亂無序列表。爲了防止這種情況發生,我試圖在這些按鈕的任何一個onClick函數正在運行期間禁用這3個按鈕中的每一個。什麼是點擊後禁用HTML按鈕的最快捷方式?

要真正將此修補程序推到極限,我已經運行了自動化測試,這些測試旨在交替重複地在兩個這些按鈕之間進行點擊。這個想法是,即使測試軟件以超人類速度在兩個按鈕之間點擊,當第一個按鈕的方法調用正在進行時,第二個按鈕也不會被點擊。

我已經嘗試了幾種方法來做到這一點 - 在每個按鈕上使用ng-disabled屬性,綁​​定到範圍級變量,每個方法在其方法的開始和結束時切換爲true和false,手動禁用每個功能開始和結束時的按鈕 - 然而在每種情況下,測試報告競爭狀態仍在觸發。

考慮到我在他們的方法調用一開始就手動禁用這些按鈕,看起來即使這還不夠。有誰知道點擊後可以禁用按鈕的絕對最早點?

回答

1

定理:

您所遇到的問題是,能夠有效地運行該腳本排隊點擊。只要在事件處理程序正在運行的瀏覽器窗口沒有響應,但則仍會記錄點擊,並儘快處理程序進行處理,

所以,你要做的就是

在handler1:

  • 禁用BUTTON2
  • 所有的處理
  • 啓用按鈕2

只有在此之後,點擊纔會被處理(即使您在事件處理期間點擊了它)。因爲那時button2被啓用,handler2也會運行。

證明:

用一塊HTML的,你可以檢查:

<button id="test1" onclick="window.test1();">Test1</button> 
<button id="test2" onclick="window.test2();">Test2</button> 

和文字:

window.test1 = function() 
{ 
    document.getElementById('test2').disabled = true; 
    for (var i=0; i<1000000000; i++); 
    document.getElementById('test2').disabled = false; 
    alert('Test1 done'); // Notice: Alert after enabling button 2. 
} 

window.test2 = function() 
{ 
    document.getElementById('test1').disabled = true; 
    for (var i=0; i<1000000000; i++); 
    alert('Test2 done'); // Notice: Alert before re-enabling button 1. 
    document.getElementById('test1').disabled = false; 
} 

兩個按鈕,他們每個人將執行一個類似的,耗時的腳本。如果您在循環運行時單擊按鈕1並快速按下按鈕2,則會注意到這兩個處理程序都被調用,但您也會看到另一個按鈕在循環期間沒有(視覺)禁用,因爲要禁用的信號該按鈕也會在稍後處理,就像點擊事件一樣。

如果先按下按鈕2(在啓用另一個按鈕之前出現消息框),則會注意到按鈕1在循環運行時未被禁用,但在消息框顯示之前它將被禁用,在消息框關閉之後保持這樣。

http://jsfiddle.net/u334tz36/1/

所以,我認爲沒有什麼解決。其實這兩個事件處理程序並不是在同一時間運行,而是在彼此之後運行,所以可能根本就沒有問題。

解決方案:

如果你仍然認爲這是煩人,你想默默消耗的點擊,您可以使用定時器做到這一點。在下面的代碼中,該按鈕在處理程序中未啓用,但在超時後運行1ms。這樣,一旦事件處理程序完成,(響應)窗口將處理所有延遲的消息。按鈕2將顯示爲禁用,點擊被禁用的按鈕消耗(和丟棄),和1毫秒之後,該按鈕被激活:

window.enableTest2 = function() 
{ 
    document.getElementById('test2').disabled = false; 
} 

window.test1 = function() 
{ 
    document.getElementById('test2').disabled = true; 
    for (var i=0; i<1000000000; i++); 
    setTimeout(window.enableTest2, 1); 
} 

http://jsfiddle.net/u334tz36/2/

有趣的事情是,你只需要讓窗口有機會檢索單擊按鈕時發送的消息。要做到這一點,你根本不需要幾秒鐘,1毫秒就足夠了,甚至可以少用幾秒鐘。您只需更改事件的順序:首先處理與禁用按鈕相關的所有更新,然後執行事件處理程序。因爲setTimeout也是基於消息的,所以它也依賴於相同的更新機制(並且實際上可以通過運行代碼來延遲。所以基本上你通過設置超時來做什麼,是將代碼放在隊列末尾的超時中,不管延遲多短,這都不是時間問題,這是一個執行順序的問題。

所以,這是一個可能的解決方法,但就像我說的,我不認爲存在首先是一個問題

+0

謝謝你這麼詳細的回答,如果可以的話,我會給予更多的讚揚,我將不得不降低測試期望。 – Argus9 2014-09-08 14:02:10

相關問題