探索 JavaScript 定時器

setTimeout()

在編寫 JavaScript 程式碼時,你可能想要延遲一個函式的執行。

這就是 setTimeout 的作用。你指定一個稍後要執行的回撥函式,以及一個表示要延遲多久的值,單位為毫秒。

(() => {
  // runs after 2 seconds
}, 2000);

(() => {
  // runs after 50 milliseconds
}, 50);

此語法定義了一個新函式。你可以在其中呼叫任何其他你想要的函式,或者你可以傳遞一個已存在的函式名和一組引數。

const  = (, ) => {
  // do something
};

// runs after 2 seconds
(, 2000, firstParam, secondParam);

在 Node.js 中,setTimeout 返回一個 Timeout 例項,而在瀏覽器中它返回一個數字定時器 ID。這個物件或 ID 可以用來取消已計劃的函式執行。

const  = (() => {
  // should run after 2 seconds
}, 2000);

// I changed my mind
();

零延遲

如果你將超時延遲指定為 0,回撥函式將盡快執行,但在當前函式執行之後。

(() => {
  .('after ');
}, 0);

.(' before ');

這段程式碼將列印:

before
after

這對於避免在密集型任務上阻塞 CPU 特別有用,它可以透過在排程器中將函式排隊,讓其他函式在執行繁重計算時得以執行。

一些瀏覽器(IE 和 Edge)實現了一個 setImmediate() 方法,它實現了完全相同的功能,但它不是標準的,並且在其他瀏覽器上不可用。但它在 Node.js 中是一個標準函式。

setInterval()

setInterval 是一個類似於 setTimeout 的函式,但有一個區別:它不是隻執行一次回撥函式,而是會以你指定的特定時間間隔(以毫秒為單位)永遠執行它。

(() => {
  // runs every 2 seconds
}, 2000);

上面的函式每 2 秒執行一次,除非你使用 clearInterval 告訴它停止,並向其傳遞 setInterval 返回的 interval id。

const  = (() => {
  // runs every 2 seconds
}, 2000);

();

通常會在 setInterval 回撥函式內部呼叫 clearInterval,讓它自動判斷是應該再次執行還是停止。例如,這段程式碼會一直執行某個東西,除非 App.somethingIWait 的值變為 arrived

const  = (() => {
  if (App.somethingIWait === 'arrived') {
    ();
  }
  // otherwise do things
}, 100);

遞迴 setTimeout

setInterval 每 n 毫秒啟動一個函式,完全不考慮函式何時完成執行。

如果一個函式總是花費相同的時間,那就沒問題。

setInterval working fine

但也許函式會因網路狀況等原因而有不同的執行時間。

setInterval varying duration

甚至可能一次長時間的執行會與下一次執行重疊。

setInterval overlapping

為了避免這種情況,你可以在回撥函式完成時安排一個遞迴的 setTimeout 來呼叫。

const  = () => {
  // do something

  (, 1000);
};

(, 1000);

以實現這種場景

Recursive setTimeout

在 Node.js 中,透過 Timers 模組 提供了 setTimeoutsetInterval

Node.js 還提供了 setImmediate(),它等同於使用 setTimeout(() => {}, 0),主要用於與 Node.js 事件迴圈協同工作。