1

SetInterval是否可以阻塞頁面中的其他腳本?JavaScript的setInterval塊可以執行線程嗎?

我正在開發一個項目,將Gmail相關書籤轉換爲Google Chrome擴展程序。小書籤使用gmail greasemonkey API與gmail頁面進行交互。 API的JavaScript對象是要加載的Gmail頁面的最後部分之一,並通過XMLHttpRequest加載到頁面中。由於我需要訪問此對象,並且全局JavaScript變量對擴展內容腳本隱藏,因此我在gmail頁面中注入了一個腳本,用於輪詢變量的定義,然後訪問它。我正在使用setInterval函數進行輪詢。這大約80%的時間工作。其餘時間輪詢功能保持輪詢,直到達到我設置的限制,並且從未在頁面中定義greasemonkey API對象。

注入腳本示例:

var attemptCount = 0; 

    var attemptLoad = function(callback) { 

     if (typeof(gmonkey) != "undefined"){ 
      clearInterval(intervalId); // unregister this function for interval execution. 
      gmonkey.load('1.0', function (gmail) { 
       self.gmail = gmail; 
       if (callback) { callback(); } 
      }); 
     } 
     else { 
      attemptCount ++; 
      console.log("Gmonkey not yet loaded: " + attemptCount); 
      if (attemptCount > 30) { 
       console.log("Could not fing Gmonkey in the gmail page after thirty seconds. Aborting"); 
       clearInterval(intervalId); // unregister this function for interval execution. 
      }; 
     } 
    }; 

    var intervalId = setInterval(function(){attemptLoad(callback);}, 1000); 
+1

那麼,在執行回調期間,不能執行其他代碼(事件處理程序,超時回調函數),因爲JavaScript是單線程的......如果這就是你的意思。 – 2012-08-15 23:09:24

回答

10

JavaScript是單線程(除了我們不是在談論這裏網絡工作者)。這意味着只要正常的JavaScript執行線程正在運行,您的setInterval()定時器將不會運行,直到執行正常的JavaScript線程完成。

同樣,如果您的setInterval()處理程序正在執行,那麼在您的setInterval()處理程序完成執行它的當前調用之前,不會觸發其他JavaScript事件處理程序。

所以,只要您的setInterval()處理程序不會卡住並永久運行,它不會阻止其他事物最終運行。它可能會稍微延遲它們,但是隻要當前的線程完成,它們仍然會運行。

在內部,JavaScript引擎使用一個隊列。當某些事情想要運行時(如事件處理程序或setInterval()回調),並且某些事件已在運行時,它會將事件插入到隊列中。當前的JavaScript線程完成執行時,JS引擎會檢查事件隊列,如果有事件發生,它將在那裏選擇最舊的事件並調用其事件處理程序。

這裏是JavaScript的事件系統是如何工作的其他一些參考:

How does JavaScript handle AJAX responses in the background?

Are calls to Javascript methods thread-safe or synchronized?

Do I need to be concerned with race conditions with asynchronous Javascript?

+0

謝謝。我知道在處理程序運行時沒有其他腳本可以運行,但是我的期望是處理程序的執行將非常簡短,並且該控制權將被放棄到任何其他腳本/事件需要運行的時間,直到經過1秒的時間間隔並再次調用處理程序。有什麼我失蹤了嗎? – 2012-08-15 23:31:02

+1

@BSharp - 這是正確的解釋。如果您的計時器腳本只是短暫運行(如幾毫秒),那麼間隔計時器的1秒間隔內的所有其餘時間可用於所有其他事件處理程序或計時器運行。 – jfriend00 2012-08-16 04:13:39

+0

這必須是關於stackoverflow的最好的setInterval()解釋。 – Donato 2016-07-15 18:31:27

4

的setInterval和setTimeout的是 「禮貌」,因爲他們不」 t當你認爲他們會 - 他們會在任何時候線程被清除時觸發,在你指定的點後。因此,調度東西的行爲不會阻止其它運行 - 它只是將自身設置爲在當前隊列的末尾運行,或者在指定時間結束時(以較長者爲準)運行。

兩個重要的注意事項:

首先將是的setTimeout/setInterval的具有特定瀏覽器的最小值。通常他們大約15ms。因此,如果你每1ms請求一次,瀏覽器實際上將它們安排爲每個browser_min_ms(不是一個真正的變量)。

第二種情況是,如果回調中的腳本比間隔時間長,那麼您可以運行到瀏覽器將繼續排隊積壓間隔的列車故障。

function doExpensiveOperation() { 
    var i = 0, l = 20000000; 
    for (; i < l; i++) { 
     doDOMStuffTheWrongWay(i); 
    } 
} 


setInterval(doExpensiveOperation, 10); 

BadTimes + = 1;

但是,對於您的代碼具體而言,沒有什麼本質上錯誤與你在做什麼。 就像我說的,setInterval不會中止任何其他事情發生,它只會注入到下一個可用的插槽中。

我可能會推薦你使用setTimeout來作爲通用的東西,但是你仍然在保持間隔標籤並保持間隔的情況下做得很好。

代碼中的其他地方可能還有其他事情正在進行,無論是在Google的投遞中,還是在您的收藏中。

相關問題