相信你們對 setInterval
, setTimeout
兩個 api 是熟悉得不能再熟悉了,它們是咱們經常使用的 web 定時器。javascript
const timer1 = setInteral(() => {
console.log(1)
}, 1000)
const timer1 = setTimeout(() => {
console.log(2)
}, 2000)
複製代碼
值得注意的是咱們在建立的定時器不用以後最好清除掉。前端
clearInterval(timer1)
clearTimeout(timer2)
複製代碼
那咱們今天來討論一下,如何實現一個定時器呢?java
關於 setTimeout, 同事給出了這樣的實現:git
邏輯也很是清晰,在函數內部構造一個循環堵住程序,等到時間到後跳出循環執行 callback,至關於開閘泄洪。es6
可是這樣寫確定是有問題的,咱們知道 js 的定時器是定義爲宏任務的,在時間循環中是不會阻塞主線程運行的,所以這種是比較 hack 的作法,沒有實現宏任務。所以這種是最早廢棄的github
若是能夠用 setInterval,setTimeout 相互實現的話,那咱們就有不少思路了web
個人 setTimeout 是這樣實現的,經過 setInterval 構造一個定時器,到第一次執行時清除定時器,執行回調函數api
咱們看一下效果函數
執行結果以下:學習
咱們看到這裏的定時器是沒有阻礙主執行粘的,基本達到了咱們的目的
當咱們實現了定時器以後,還有一個問題,咱們的定時器是沒法消除的,爲了能夠有添加定時器、清除定時器、清除所有定時器等操做,我決定經過 es6 的類來實現
思路中的大體結構是這樣,咱們維護一個定時器棧,這個類有 add,run,clear,clearAll 等方法,能夠添加,清除,運行定時器,有了這個思路以後咱們一步一步來實現
原理很簡單,添加定時器就是直接把數據推入咱們的棧中,推入前須要作一下簡單的數據校驗
經過 name 在棧中查找,找到對應的定時器以後執行,這裏須要用到 setTimeout 來實現 setInterval,執行方式和上面同樣。
原理就是找到對應的定時器,在棧中刪掉,這樣在 run 的遞歸函數中找不到對應的定時器就沒法執行。清除所有定時器直接清空棧就好。
到這裏咱們實現了一個簡單的 setInterval
咱們來看一下效果:
能夠看到 4.5s 以後定時器被清除了
到這裏咱們就實現了一個簡單的定時器,你能夠寫一個 本身的 setTimeout 嗎?
關注 前端 100 問,一塊兒學習,持續擴展中