相信大家在寫Javascript時常常會用到Timer,一定會馬上想到用setInterval這個異步方法。然而,你有沒想過用setTimeout加上遞迴的方式去實作一個setInterval,孰優孰劣?

最近剛好有個需求要使用setInterval來觸發事件,所以查了一下發現有人用setTimeout來實現setInterval,當時就在想為什麼要大費周章去實作呢?事出必有因,經過Google後,讓我認識了裡面的意義,若你還不知,希望這篇短文讓你長點知識。

異步Timer的注意事項

若要實作一個異步Timer,通常會考量這兩個層面:

  • 準確性(時間)
  • 完整性(資料)

這邊說明一下,時間的準確性就是每次的循環都非常的準確,沒有任何的誤差。例如:每次以一秒來循環,程式要求每秒鐘一定要準時觸發事件。完整性就是指,所觸發的事件若反應時間過慢,超過了等待時間,依然要能保證資料回覆的完整性。也就是說這兩這基本上是互斥的。你要保證準確性,就無法保證完整性。反之亦然。說一下小結:所以在javascript的世界中,你若想要確保準確性,請使用setInterval。若想確保完整性,請用setTimeout實作。做一個小表格如下:

Timer特性setIntervalsetTimeout
準確性V
完整性V

使用場景

好了,說了那麼多,直接介紹一些使用場景吧。簡單的說就是如果你的間隔時間越短越建議使用setTimeout來實作Timer,因為你逾時的機率很大。或者,所觸發的事件不可預期且時間較長(I/O bound),像是一個ajax請求等等。這時候非常建議使用setTimeout。還有一種場景,一定要保證資料不會漏失,例如背景作業來追蹤使用者行為等等。其他的時候其實使用setInterval就可以了。

用setTimeout實作Timer

最後附上一小段用setTimeout實作Timer的code:

Timer(method, time) {
    let timeout;
    function loop() {
    timeout = setTimeout(function() {
        method();
        loop();
    }, time);
    }
    loop();
    return {
        cancel: function cancel() {
            clearTimeout(timeout);
        }
    };
}

PK結果沒有孰優孰劣,完全看你要使用的場景是什麼喔~謝謝大家。