欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

javascript 定時(shí)器工作原理分析

 更新時(shí)間:2016年12月03日 23:09:59   作者:mcbird  
說(shuō)到 javascript 中的定時(shí)器,我們肯定會(huì)想到 setTimeout() 和 setInterval() 這兩個(gè)函數(shù)。本文將從 事件循環(huán)(Event Loop) 的角度來(lái)分析兩者的工作原理和區(qū)別

setTimeout()

MDN對(duì) setTimeout 的定義為:

在指定的延遲時(shí)間之后調(diào)用一個(gè)函數(shù)或執(zhí)行一個(gè)代碼片段。

語(yǔ)法

setTimeout 的語(yǔ)法非常簡(jiǎn)單,第一個(gè)參數(shù)為回調(diào)函數(shù),第二個(gè)參數(shù)為延時(shí)的時(shí)間。函數(shù)返回一個(gè)數(shù)值類型的ID唯一標(biāo)示符,此ID可以用作 clearTimeout 的參數(shù)來(lái)取消定時(shí)器:

var timeoutID = window.setTimeout(code, delay);

IE0+ 還支持回調(diào)參數(shù)的傳入:

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);

setInterval()

MDN 對(duì) setInterval 的定義為:

周期性地調(diào)用一個(gè)函數(shù)(function)或者執(zhí)行一段代碼。

由于 setInterval 和 setTimeout 的用法一樣,所以這里不再列出。

對(duì)第二個(gè)參數(shù)(delay)的說(shuō)明

由于javascript 的事件循環(huán)機(jī)制,導(dǎo)致第二個(gè)參數(shù)并不代表延遲delay毫秒之后立即執(zhí)行回調(diào)函數(shù),而是嘗試將回調(diào)函數(shù)加入到事件隊(duì)列。實(shí)際上,setTimeout 和 setInterval 在這一點(diǎn)上處理又存在區(qū)別:

  • setTimeout:延時(shí)delay毫秒之后,啥也不管,直接將回調(diào)函數(shù)加入事件隊(duì)列。
  • setInterval: 延時(shí)delay毫秒之后,先看看事件隊(duì)列中是否存在還沒(méi)有執(zhí)行的回調(diào)函數(shù)(setInterval的回調(diào)函數(shù)),如果存在,就不要再往事件隊(duì)列里加入回調(diào)函數(shù)了。

所以,當(dāng)我們的代碼中存在耗時(shí)的任務(wù)時(shí),定時(shí)器并不會(huì)表現(xiàn)的如我們所想的那樣。

通過(guò)一個(gè)例子來(lái)理解

下面的代碼,本來(lái)希望能夠在 100ms 和 200ms 的時(shí)候(也就是剛好等待 100ms)調(diào)用回調(diào)函數(shù):

var timerStart1 = now();
setTimeout(function () {
 console.log('第一個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間:', now() - timerStart1);

 var timerStart2 = now();
 setTimeout(function () {
  console.log('第二個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間:', now() - timerStart2);
 }, 100);
}, 100);
// 輸出:
// 第一個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間: 106
// 第二個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間: 107

這樣的結(jié)果看上去正是我們所想的那樣,但是一旦我們?cè)诖a中加入了耗時(shí)的任務(wù)時(shí)候,結(jié)果就不像我們所期望的那樣了:

var timerStart1 = now();
setTimeout(function () {
 console.log('第一個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間:', now() - timerStart1);

 var timerStart2 = now();
 setTimeout(function () {
  console.log('第二個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間:', now() - timerStart2);
 }, 100);

 heavyTask(); // 耗時(shí)任務(wù)
}, 100);

var loopStart = now();
heavyTask(); // 耗時(shí)任務(wù)
console.log('heavyTask耗費(fèi)時(shí)間:', now() - loopStart);

function heavyTask() {
 var s = now();
 while(now() - s < 1000) {
 }
}

function now () {
 return new Date();
}
// 輸出:
// heavyTask耗費(fèi)時(shí)間: 1015
// 第一個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間: 1018
// 第二個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間: 1000

兩個(gè) setTimeout 的等待事件由于耗時(shí)任務(wù)的存在不再是 100ms 了!我們來(lái)描述一下事情的經(jīng)過(guò):

  1. 首先,第一個(gè)耗時(shí)任務(wù)(heavyTask())開始執(zhí)行,它需要大約 1000ms 才能執(zhí)行完畢。
  2. 從耗時(shí)任務(wù)開始執(zhí)行,過(guò)了 100ms, 第一個(gè) setTimeout 的回調(diào)函數(shù)期望執(zhí)行,于是被加入到事件隊(duì)列,但是此時(shí)前面的耗時(shí)任務(wù)還沒(méi)執(zhí)行完,所以它只能在隊(duì)列中等待,直到耗時(shí)任務(wù)執(zhí)行完畢它才開始執(zhí)行,所以結(jié)果中我們開的看到的是: 第一個(gè)setTimeout回調(diào)執(zhí)行等待時(shí)間: 1018。
  3. 第一個(gè) setTimeout 回調(diào)一執(zhí)行,又開啟了第二個(gè) setTimeout, 這個(gè)定時(shí)器也是期望延時(shí) 100ms 之后能夠執(zhí)行它的回調(diào)函數(shù)。 但是,在第一個(gè) setTimeout 又存在一個(gè)耗時(shí)任務(wù),所有它的劇情跟第一個(gè)定時(shí)器一樣,也等待了 1000ms 才開始執(zhí)行。

可以用下面的圖來(lái)概括:

再來(lái)看 setInterval 的一個(gè)例子:

var intervalStart = now();
setInterval(function () {
 console.log('interval距定義定時(shí)器的時(shí)間:', now() - loopStart);
}, 100);

var loopStart = now();
heavyTask();
console.log('heavyTask耗費(fèi)時(shí)間:', now() - loopStart);

function heavyTask() {
 var s = now();
 while(now() - s < 1000) {
 }
}

function now () {
 return new Date();
}
// 輸出:
// heavyTask耗費(fèi)時(shí)間: 1013
// interval距定義定時(shí)器的時(shí)間: 1016
// interval距定義定時(shí)器的時(shí)間: 1123
// interval距定義定時(shí)器的時(shí)間: 1224

上面這段代碼,我們期望每隔 100ms 就打出一條日志。相對(duì)于 setTimeout 的區(qū)別, setInterval 在準(zhǔn)備把回調(diào)函數(shù)加入到事件隊(duì)列的時(shí)候,會(huì)判斷隊(duì)列中是否還有未執(zhí)行的回調(diào),如果有的話,它就不會(huì)再往隊(duì)列中添加回調(diào)函數(shù)。 不然,會(huì)出現(xiàn)多個(gè)回調(diào)同時(shí)執(zhí)行的情況。

可以用下面的圖來(lái)概括:

總結(jié)

上面對(duì)javascript定時(shí)器執(zhí)行原理進(jìn)行了簡(jiǎn)要的分析,希望能夠幫助我們更深入的理解javascript。文中有描述不當(dāng)?shù)牡胤娇梢栽谠u(píng)論中指出。

相關(guān)文章

  • Javascript字符串拼接小技巧(推薦)

    Javascript字符串拼接小技巧(推薦)

    下面小編就為大家?guī)?lái)一篇Javascript字符串拼接小技巧(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-06-06
  • javascript實(shí)現(xiàn)支持移動(dòng)設(shè)備畫廊

    javascript實(shí)現(xiàn)支持移動(dòng)設(shè)備畫廊

    本文通過(guò)純javascript技術(shù)實(shí)現(xiàn)支持移動(dòng)設(shè)備畫廊,支持移動(dòng)設(shè)備手勢(shì)操作,感興趣的朋友一起來(lái)學(xué)習(xí)吧
    2015-08-08
  • 基于JavaScript實(shí)現(xiàn)數(shù)值型坐標(biāo)軸刻度計(jì)算算法(echarts的y軸刻度計(jì)算)

    基于JavaScript實(shí)現(xiàn)數(shù)值型坐標(biāo)軸刻度計(jì)算算法(echarts的y軸刻度計(jì)算)

    這篇文章主要介紹了基于JavaScript實(shí)現(xiàn)數(shù)值型坐標(biāo)軸刻度計(jì)算算法(echarts的y軸刻度計(jì)算),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,感興趣的朋友可以參考與一下
    2022-06-06
  • 淺談Javascript線程及定時(shí)機(jī)制

    淺談Javascript線程及定時(shí)機(jī)制

    這篇文章主要介紹了淺談Javascript線程及定時(shí)機(jī)制的相關(guān)資料,需要的朋友可以參考下
    2015-07-07
  • TypeScript中import?type與import的區(qū)別詳析

    TypeScript中import?type與import的區(qū)別詳析

    ES6引入了模塊化,其設(shè)計(jì)思想是在編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量,下面這篇文章主要給大家介紹了關(guān)于TypeScript中import?type與import區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • 比較詳細(xì)的關(guān)于javascript中void(0)的具體含義解釋

    比較詳細(xì)的關(guān)于javascript中void(0)的具體含義解釋

    比較詳細(xì)的關(guān)于javascript中void(0)的具體含義解釋...
    2007-08-08
  • javascript仿php的print_r函數(shù)輸出json數(shù)據(jù)

    javascript仿php的print_r函數(shù)輸出json數(shù)據(jù)

    輸出json數(shù)據(jù),php的print_r函數(shù)可以輕松實(shí)現(xiàn),下面為大家介紹下javascript也可以模仿print_r函數(shù)輸出json數(shù)據(jù),具體實(shí)現(xiàn)如下,感興趣的朋友可以了解下
    2013-09-09
  • Java SE 9 多版本兼容 JAR 包示例

    Java SE 9 多版本兼容 JAR 包示例

    這篇文章主要介紹了Java SE 9 多版本兼容 JAR 包示例,Java 9 版本中增強(qiáng)了Jar 包多版本字節(jié)碼文件格式支持,也就是說(shuō)在同一個(gè) Jar 包中我們可以包含多個(gè) Java 版本的 class 文件,更多相關(guān)內(nèi)容感興趣的小伙伴可以參考一下
    2022-08-08
  • 如何基于JS實(shí)現(xiàn)Ajax并發(fā)請(qǐng)求的控制詳解

    如何基于JS實(shí)現(xiàn)Ajax并發(fā)請(qǐng)求的控制詳解

    通常為了減少頁(yè)面加載時(shí)間,先把核心內(nèi)容顯示處理,頁(yè)面加載完成后再發(fā)送ajax請(qǐng)求獲取其他數(shù)據(jù),這時(shí)就可能產(chǎn)生多個(gè)ajax請(qǐng)求,為了用戶體驗(yàn),最好是發(fā)送并行請(qǐng)求,這篇文章主要給大家介紹了關(guān)于如何基于JS實(shí)現(xiàn)Ajax并發(fā)請(qǐng)求控制的相關(guān)文章,需要的朋友可以參考下
    2021-08-08
  • js+canvas簡(jiǎn)單繪制圓圈的方法

    js+canvas簡(jiǎn)單繪制圓圈的方法

    這篇文章主要介紹了js+canvas簡(jiǎn)單繪制圓圈的方法,涉及JavaScript調(diào)用canvas組件實(shí)現(xiàn)簡(jiǎn)單圖形繪制的相關(guān)技巧,需要的朋友可以參考下
    2016-01-01

最新評(píng)論