1. 程式人生 > >Javascript學習---排程:setTimeout&&setInterval

Javascript學習---排程:setTimeout&&setInterval

setTimeout&&setInterval

有時候我們不想要馬上執行函式,而是在未來的特定時間裡執行,這就涉及到排程問題,Javascript提供了setTimeout和setInterval這兩個函式:

(1)setTimeout:允許在指定的時間間隔之後執行函式(一次);

(2)setInterval:允許在執行期間定期地執行函式(多次);


setTimeout

setTimeout的語法如下:

let timerId = setTimeout(func|code, delay[, arg1, arg2...])

其中func|code需要執行的函式或字串程式碼;delay是延遲執行的時間,以毫秒為單位;arg1,arg2...指定是被排程函式的引數。


延遲一秒後執行的例子:

function sayHi() {
  alert('Hello');
}

setTimeout(sayHi, 1000);

設定執行函式引數:

function sayHi(phrase, who) {
  alert( phrase + ', ' + who );
}

setTimeout(sayHi, 1000, "Hello", "John"); // Hello, John


如果setTimeout的第一個引數是字串程式碼,則Javascript預設根據程式碼生成一個函式,例如:

setTimeout("alert('Hello')", 1000);

但是使用字串程式碼的形式是不推薦的,我們可以使用箭頭函式來代替它,例如:

setTimeout(() => alert('Hello'), 1000);


需要注意的是,有時候我們可能會在執行函式後面加多個括號“()”,這樣setTimeout函式會報錯,例如:

// wrong!
setTimeout(sayHi(), 1000);  //undefined

這是因為setTimeout接受的是一個函式的引用,引用的值會傳遞給setTimeout。但如果是一個函式的話,由於sayHi()不返回任何值,故沒有傳遞值給setTimeout,所以結果是undefined


取消排程clearTimeout

我們使用setTimeout來設定排程後,也可以通過clearTimeout來取消排程,例如:

let timerId = setTimeout(...);
clearTimeout(timerId);

由於每次使用setTimeout後都會預設返回一個識別符號,所以取消排程的會則要通過這個識別符號


再看下面的例子:

let timerId = setTimeout(() => alert("never happens"), 1000);
alert(timerId); // timer identifier

clearTimeout(timerId);
alert(timerId); // same identifier (doesn't become null after canceling)

從上面的結果中可以看出,在瀏覽器中timerId是一個數字,而在其他環境中可能會是其他型別資料,例如在Node.js會返回一個附帶其他方法的timer物件


setInterval

setInterval和setTimeout有一樣的語法:

let timerId = setInterval(func|code, delay[, arg1, arg2...])

但是有一點不同的是setInterval會在時間間隔後定期執行,不是隻有一次


為了取消setInterval,我們可以使用clearInterval,例如:

// repeat with the interval of 2 seconds
let timerId = setInterval(() => alert('tick'), 2000);

// after 5 seconds stop
setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);

遞迴的setTimeout

前面我們已經知道了,setTimeout僅僅執行一次,為了達到setInterval的效果,我們可以遞迴地使用setTimeout,例如:

/** instead of:
let timerId = setInterval(() => alert('tick'), 2000);
*/

let timerId = setTimeout(function tick() {
  alert('tick');
  timerId = setTimeout(tick, 2000); // (*)
}, 2000);
相比於setInterval,遞迴使用setTimeout可能更加靈活,因為我們還可以在遞迴中修改delay時間


遞迴使用setTimeout嚴格保證了執行函式被排程的時間間隔,而setInterval卻不能嚴格保證,看下面兩個例子:

let i = 1;
setInterval(function() {
  func(i);
}, 100);
let i = 1;
setTimeout(function run() {
  func(i);
  setTimeout(run, 100);
}, 100);

第一個例子中,func()會在每隔100毫秒後被呼叫,無論func()有沒有執行完,若func()執行時間大於間隔時間,那麼就會出現疊加呼叫的情況,即第一次呼叫的func()還沒執行完,func()的第二次呼叫就開始了;第二個例子中,func()每次執行完後的100毫秒後再次被呼叫。因此,我們應該根據具體情況使用setInterval和遞迴的setInterval


setTimeout(…,0)情況

這裡有一個特殊的情況,當使用setTimeout(...,0)時,它會在當前的其他程式碼執行完後再執行,也就是非同步,例如:

setTimeout(() => alert("World"), 0);

alert("Hello");
這裡它會先輸出"Hello",再輸出"World"