摘要:說到中的定時器,我們肯定會想到和這兩個函數。第一個回調一執行,又開啟了第二個,這個定時器也是期望延時之后能夠執行它的回調函數??梢杂孟旅娴膱D來概括總結上面對定時器執行原理進行了簡要的分析,希望能夠幫助我們更深入的理解。
說到 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。文中有描述不當的地方可以在評論中指出。
文章地址:http://blog.mcbird.cn/2015/09/18/javascript-timers/
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85989.html
摘要:創建了一個簡單的計時器,在經過給定的時間后,回調函數將會被執行。接受一個計時器由之前兩種計時器返回并且停止計時器回調函數的執行。然而,我們可以注意到,當定時器再一次觸發在計時器回調函數正在執行的時候,這一次定時器回調函數被丟棄了。 最近都在看一些JavaScript原理層面的文章,恰巧看到了jQuery的作者的一篇關于JavaScript計時器原理的解析,于是誠惶誠恐地決定把原文翻譯成...
摘要:一什么是定時器提供了一些原生方法來實現延時去執行某一段代碼,下面來簡單介紹一下設置一個定時器,在定時器到期后執行一次函數或代碼段定時器延遲后執行的函數延遲后執行的代碼字符串,不推薦使用原理類似延遲的時間單位毫秒,默認值為向延遲函數傳遞而外的 一、什么是定時器 JS提供了一些原生方法來實現延時去執行某一段代碼,下面來簡單介紹一下 setTimeout: 設置一個定時器,在定時器到期后執行...
摘要:函數會在之后的某個時刻觸發事件定時器。事件循環中的這樣一次遍歷被稱為一個。執行完畢并出棧。當定時器過期,宿主環境會把回調函數添加至事件循環隊列中,然后,在未來的某個取出并執行該事件。 原文請查閱這里,略有改動。 本系列持續更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第四章。 現在,我們將會通過回顧單線程環境下編程的弊端及如何克服這些困難以創建令人驚嘆...
摘要:這兩個函數接受定時器的例如我們上面提到的兩個函數產生的定時器,并停止對定時器中指定函數的調用。注意,定時器雖然觸發了,但是并不會立即執行,它只是把需要延遲執行的函數加入了執行隊列,在線程的某一個可用的時間點,這個函數就能夠得到執行。 擼了今年阿里、頭條和美團的面試,我有一個重要發現....... javascript定時器工作原理是一個重要的基礎知識點。因為定時器在單線程中工作,它們表...
閱讀 1156·2023-04-25 17:28
閱讀 3531·2021-10-14 09:43
閱讀 3955·2021-10-09 10:02
閱讀 1943·2019-08-30 14:04
閱讀 3129·2019-08-30 13:09
閱讀 3270·2019-08-30 12:53
閱讀 2896·2019-08-29 17:11
閱讀 1823·2019-08-29 16:58