Window: setInterval() 方法

Baseline 廣泛可用 *

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

* 此特性的某些部分可能存在不同級別的支援。

Window 介面的 setInterval() 方法重複呼叫一個函式或執行一個程式碼片段,在每次呼叫之間都有固定的時間延遲。

語法

js
setInterval(code)
setInterval(code, delay)

setInterval(func)
setInterval(func, delay)
setInterval(func, delay, arg1)
setInterval(func, delay, arg1, arg2)
setInterval(func, delay, arg1, arg2, /* …, */ argN)

引數

func

一個 function,每隔 delay 毫秒執行一次。第一次執行發生在 delay 毫秒之後。

code

一個可選的語法允許你包含一個字串而不是一個函式,該字串每隔 delay 毫秒被編譯和執行。出於與使用 eval() 造成安全風險相同的原因,不推薦使用此語法。

delay 可選

計時器在每次執行指定函式或程式碼之間應該延遲的時間,單位為毫秒(千分之一秒)。如果未指定,則預設為 0。有關 delay 值的允許範圍的詳細資訊,請參閱下面的延遲限制

arg1, …, argN 可選

計時器到期後,將傳遞給 func 指定函式的附加引數。

返回值

setInterval() 方法返回一個正整數(通常在 1 到 2,147,483,647 之間),該整數唯一標識透過呼叫建立的間隔計時器。此識別符號(通常稱為“間隔 ID”)可以傳遞給 clearInterval() 以停止指定函式的重複執行。

在同一個全域性環境(例如,特定的視窗或 Worker)中,只要原始計時器仍然處於活動狀態,間隔 ID 就被確保保持唯一,並且不會為任何新的間隔計時器重複使用。然而,不同的全域性環境維護它們自己獨立的間隔 ID 池。

請注意,setInterval()setTimeout() 共享相同的 ID 池,並且 clearInterval()clearTimeout() 在技術上可以互換使用。然而,為了清晰起見,你應該始終嘗試將它們匹配起來,以避免在維護程式碼時產生混淆。

注意: delay 引數被轉換為一個有符號的 32 位整數。這有效地將 delay 限制在 2147483647 毫秒(大約 24.8 天),因為它在 IDL 中被指定為有符號整數。

示例

示例 1:基本語法

以下示例演示了 setInterval() 的基本語法。

js
const intervalID = setInterval(myCallback, 500, "Parameter 1", "Parameter 2");

function myCallback(a, b) {
  // Your code here
  // Parameters are purely optional.
  console.log(a);
  console.log(b);
}

示例 2:交替兩種顏色

以下示例每秒呼叫 flashtext() 函式一次,直到按下停止按鈕。

HTML

html
<div id="my_box">
  <h3>Hello World</h3>
</div>
<button id="start">Start</button>
<button id="stop">Stop</button>

CSS

css
.go {
  color: green;
}
.stop {
  color: red;
}

JavaScript

js
// variable to store our intervalID
let intervalId;

function changeColor() {
  // check if an interval has already been set up
  intervalId ??= setInterval(flashText, 1000);
}

function flashText() {
  const oElem = document.getElementById("my_box");
  oElem.className = oElem.className === "go" ? "stop" : "go";
}

function stopTextColor() {
  clearInterval(intervalId);
  // release our intervalId from the variable
  intervalId = null;
}

document.getElementById("start").addEventListener("click", changeColor);
document.getElementById("stop").addEventListener("click", stopTextColor);

結果

“this”問題

當你將一個方法傳遞給 setInterval() 或任何其他函式時,它會以錯誤的 this 值被呼叫。這個問題在 JavaScript 參考中有詳細解釋。

解釋

setInterval() 執行的程式碼執行在與呼叫它的函式不同的執行上下文。因此,被呼叫函式的 this 關鍵字被設定為 window(或 global)物件,它與呼叫 setTimeout 的函式的 this 值不同。請參見以下示例(它使用 setTimeout() 而不是 setInterval() ——實際上,對於這兩個計時器來說,問題是相同的)

js
myArray = ["zero", "one", "two"];

myArray.myMethod = function (sProperty) {
  alert(arguments.length > 0 ? this[sProperty] : this);
};

myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"
setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1.5 seconds

// Passing the 'this' object with .call won't work
// because this will change the value of this inside setTimeout itself
// while we want to change the value of this inside myArray.myMethod.
// In fact, it will be an error because setTimeout code expects this to be the window object:
setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error

如你所見,在傳統 JavaScript 中,沒有辦法將 this 物件傳遞給回撥函式。

一種可能的解決方案

所有現代 JavaScript 執行時(在瀏覽器和其他地方)都支援帶有詞法 this箭頭函式——允許我們寫 setInterval(() => this.myMethod()),如果我們在 myArray 方法內部。

如果你需要支援 IE,請使用 Function.prototype.bind() 方法,它允許你指定應該用作給定函式所有呼叫的 this 值。這可以讓你輕鬆繞過 this 值不明確的問題,具體取決於呼叫函式的上下文。

用法說明

setInterval() 函式通常用於為反覆執行的函式(例如動畫)設定延遲。你可以使用 clearInterval() 取消間隔。

如果你希望在指定延遲之後 呼叫一次函式,請使用 setTimeout()

延遲限制

間隔可以巢狀;也就是說,setInterval() 的回撥可以反過來呼叫 setInterval() 來啟動另一個間隔執行,即使第一個間隔仍在執行。為了減輕這可能對效能造成的影響,一旦間隔巢狀超過五層深,瀏覽器將自動強制間隔的最小值為 4 毫秒。在深度巢狀的 setInterval() 呼叫中嘗試指定小於 4 毫秒的值將被固定為 4 毫秒。

在某些情況下,瀏覽器可能會對間隔強制執行更嚴格的最小值,儘管這些情況不常見。另請注意,回撥之間實際經過的時間可能比給定的 delay 長;有關示例,請參閱延遲時間長於指定時間的原因

確保執行持續時間短於間隔頻率

如果你的邏輯執行時間可能比間隔時間長,建議使用 setTimeout() 遞迴呼叫一個命名函式。例如,如果使用 setInterval() 每 5 秒輪詢一次遠端伺服器,網路延遲、無響應的伺服器以及許多其他問題可能會阻止請求在指定時間內完成。因此,你可能會發現自己有排隊的 XHR 請求,它們不一定會按順序返回。

在這些情況下,首選遞迴 setTimeout() 模式

js
(function loop() {
  setTimeout(() => {
    // Your logic here

    loop();
  }, delay);
})();

在上面的程式碼片段中,宣告並立即執行了一個命名函式 loop()。在邏輯完成執行後,loop()setTimeout() 內部被遞迴呼叫。雖然這種模式不保證在固定間隔執行,但它確實保證在上一個間隔完成之前進行遞迴。

規範

規範
HTML
# dom-setinterval-dev

瀏覽器相容性

另見