javascript 定時器工作原理
說到 javascript 中的定時器,我們肯定會想到 setTimeout() 和 setInterval() 這兩個函式。本文將從 事件迴圈(Event Loop) 的角度來分析兩者的工作原理和區別。
setTimeout()
MDN對 setTimeout 的定義為:
在指定的延遲時間之後呼叫一個函式或執行一個程式碼片段。
語法
setTimeout 的語法非常簡單,第一個引數為回撥函式,第二個引數為延時的時間。函式返回一個數值型別的ID唯一標示符,此ID可以用作 clearTimeout 的引數來取消定時器:
var timeoutID = window.setTimeout(code, delay);
IE0+ 還支援回撥引數的傳入:
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
setInterval()
MDN 對 setInterval 的定義為:
週期性地呼叫一個函式(function)或者執行一段程式碼。
由於 setInterval 和 setTimeout 的用法一樣,所以這裡不再列出。
對第二個引數(delay)的說明
由於javascript 的事件迴圈機制,導致第二個引數並不代表延遲delay毫秒之後立即執行回撥函式,而是嘗試將回撥函式加入到事件佇列。實際上,setTimeout 和 setInterval 在這一點上處理又存在區別:
- setTimeout:延時delay毫秒之後,啥也不管,直接將回撥函式加入事件佇列。
- setInterval: 延時delay毫秒之後,先看看事件佇列中是否存在還沒有執行的回撥函式(setInterval的回撥函式),如果存在,就不要再往事件佇列里加入回撥函式了。
所以,當我們的程式碼中存在耗時的任務時,定時器並不會表現的如我們所想的那樣。
通過一個例子來理解
下面的程式碼,本來希望能夠在 100ms 和 200ms 的時候(也就是剛好等待 100ms)呼叫回撥函式:
var timerStart1 = now(); setTimeout(function () { console.log('第一個setTimeout回撥執行等待時間:', now() - timerStart1); var timerStart2 = now(); setTimeout(function () { console.log('第二個setTimeout回撥執行等待時間:', now() - timerStart2); }, 100); }, 100); // 輸出: // 第一個setTimeout回撥執行等待時間: 106 // 第二個setTimeout回撥執行等待時間: 107
這樣的結果看上去正是我們所想的那樣,但是一旦我們在程式碼中加入了耗時的任務時候,結果就不像我們所期望的那樣了:
var timerStart1 = now(); setTimeout(function () { console.log('第一個setTimeout回撥執行等待時間:', now() - timerStart1); var timerStart2 = now(); setTimeout(function () { console.log('第二個setTimeout回撥執行等待時間:', now() - timerStart2); }, 100); heavyTask(); // 耗時任務 }, 100); var loopStart = now(); heavyTask(); // 耗時任務 console.log('heavyTask耗費時間:', now() - loopStart); function heavyTask() { var s = now(); while(now() - s < 1000) { } } function now () { return new Date(); } // 輸出: // heavyTask耗費時間: 1015 // 第一個setTimeout回撥執行等待時間: 1018 // 第二個setTimeout回撥執行等待時間: 1000
兩個 setTimeout 的等待事件由於耗時任務的存在不再是 100ms 了!我們來描述一下事情的經過:
- 首先,第一個耗時任務(heavyTask())開始執行,它需要大約 1000ms 才能執行完畢。
- 從耗時任務開始執行,過了 100ms, 第一個 setTimeout 的回撥函式期望執行,於是被加入到事件佇列,但是此時前面的耗時任務還沒執行完,所以它只能在佇列中等待,直到耗時任務執行完畢它才開始執行,所以結果中我們開的看到的是: 第一個setTimeout回撥執行等待時間: 1018。
- 第一個 setTimeout 回撥一執行,又開啟了第二個 setTimeout, 這個定時器也是期望延時 100ms 之後能夠執行它的回撥函式。 但是,在第一個 setTimeout 又存在一個耗時任務,所有它的劇情跟第一個定時器一樣,也等待了 1000ms 才開始執行。
可以用下面的圖來概括:
再來看 setInterval 的一個例子:
var intervalStart = now(); setInterval(function () { console.log('interval距定義定時器的時間:', now() - loopStart); }, 100); var loopStart = now(); heavyTask(); console.log('heavyTask耗費時間:', now() - loopStart); function heavyTask() { var s = now(); while(now() - s < 1000) { } } function now () { return new Date(); } // 輸出: // heavyTask耗費時間: 1013 // interval距定義定時器的時間: 1016 // interval距定義定時器的時間: 1123 // interval距定義定時器的時間: 1224
上面這段程式碼,我們期望每隔 100ms 就打出一條日誌。相對於 setTimeout 的區別, setInterval 在準備把回撥函式加入到事件佇列的時候,會判斷佇列中是否還有未執行的回撥,如果有的話,它就不會再往佇列中新增回撥函式。 不然,會出現多個回撥同時執行的情況。
可以用下面的圖來概括:
總結
上面對javascript定時器執行原理進行了簡要的分析,希望能夠幫助我們更深入的理解javascript。文中有描述不當的地方可以在評論中指出。
相關文章
- JavaScript 定時器函式非同步原理JavaScript定時器函式非同步
- JavaScript定時器JavaScript定時器
- JavaScript 定時器JavaScript定時器
- JavaScript定時器演示JavaScript定時器
- JavaScript6:定時器JavaScript定時器
- javascript引擎工作原理JavaScript
- 輪播圖(JavaScript定時器)JavaScript定時器
- 【JavaScript基礎】Js的定時器(你想看的原理也在喲)JavaScriptJS定時器
- javascript怎麼清除所有定時器JavaScript定時器
- 1.15 JavaScript6:定時器JavaScript定時器
- JavaScript的工作原理:引擎,執行時和呼叫堆疊JavaScript
- JavaScript 工作原理之一-引擎,執行時,呼叫堆疊(譯)JavaScript
- 【JavaScript定時器小案例】常見的幾種定時器實現的案例JavaScript定時器
- NTP時間同步伺服器(時鐘同步)工作原理介紹伺服器
- 從零開始再學 JavaScript 定時器JavaScript定時器
- JavaScript筆記12:控制CSS、事件、定時器JavaScript筆記CSS事件定時器
- javascript定時器函式簡單介紹JavaScript定時器函式
- JavaScript定時器與執行機制解析JavaScript定時器
- 路由器工作原理路由器
- 【譯】JavaScript的工作原理:引擎,執行時和呼叫堆疊的概述JavaScript
- Javascript 定時器呼叫傳遞引數的方法JavaScript定時器
- JavaScript淺析 -- 定時器和節流防抖JavaScript定時器
- 【翻譯】JavaScript原型繼承工作原理JavaScript原型繼承
- 聚合路由器工作原理路由器
- 梳理瀏覽器工作原理瀏覽器
- SpringBoot原始碼解析-Scheduled定時器的原理Spring Boot原始碼定時器
- 定時器定時器
- javascript定時器(setTimeout和setInterval)的使用詳解JavaScript定時器
- javaScript(js)手寫原生任務定時器原始碼JavaScriptJS定時器原始碼
- javascript基礎(定時器的應用)(四十三)JavaScript定時器
- JavaScript 中 this 的工作原理以及注意事項JavaScript
- JavaScript中this的工作原理以及注意事項JavaScript
- JavaScript 計時器JavaScript
- 定時器以及定時器的幾個案例定時器
- 深入 Java Timer 定時排程器實現原理Java
- 瀏覽器工作原理(22) - JavaScript是如何影響DOM樹構建的?瀏覽器JavaScript
- 【瀏覽器】瀏覽器基本工作原理瀏覽器
- [譯]瀏覽器工作原理探究瀏覽器