成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript的計(jì)時(shí)器的工作原理

geekzhou / 1465人閱讀

摘要:創(chuàng)建了一個(gè)簡(jiǎn)單的計(jì)時(shí)器,在經(jīng)過(guò)給定的時(shí)間后,回調(diào)函數(shù)將會(huì)被執(zhí)行。接受一個(gè)計(jì)時(shí)器由之前兩種計(jì)時(shí)器返回并且停止計(jì)時(shí)器回調(diào)函數(shù)的執(zhí)行。然而,我們可以注意到,當(dāng)定時(shí)器再一次觸發(fā)在計(jì)時(shí)器回調(diào)函數(shù)正在執(zhí)行的時(shí)候,這一次定時(shí)器回調(diào)函數(shù)被丟棄了。

最近都在看一些JavaScript原理層面的文章,恰巧看到了jQuery的作者的一篇關(guān)于JavaScript計(jì)時(shí)器原理的解析,于是誠(chéng)惶誠(chéng)恐地決定把原文翻譯成中文,一來(lái)是為了和大家分享,二來(lái)是為了加深自己對(duì)于JavaScript的理解。原文鏈接:http://ejohn.org/blog/how-javascript-timers-work/

原文翻譯:

從基礎(chǔ)層面來(lái)講,理解JavaScript計(jì)時(shí)器的工作原理是很重要的。由于JavaScript是單線(xiàn)程的,所以很多時(shí)候計(jì)時(shí)器并不是表現(xiàn)得和我們的直觀(guān)想象一樣。讓我們從下面的三個(gè)函數(shù)開(kāi)始,它們能夠讓我們有機(jī)會(huì)去構(gòu)造和操作計(jì)時(shí)器。

var id =setTimeout(fn, delay); 創(chuàng)建了一個(gè)簡(jiǎn)單的計(jì)時(shí)器,在經(jīng)過(guò)給定的時(shí)間后,回調(diào)函數(shù)將會(huì)被執(zhí)行。這個(gè)函數(shù)會(huì)返回一個(gè)唯一的ID,便于在之后某個(gè)時(shí)間可以注銷(xiāo)這個(gè)計(jì)時(shí)器。

var id = setInterval(fn, delay); -和setTimeout類(lèi)似,但是每經(jīng)過(guò)一段時(shí)間(給定的延時(shí)),所傳遞的函數(shù)就會(huì)被執(zhí)行一次,直到這個(gè)定時(shí)器被注銷(xiāo)。

clearInterval(id); clearTimeout(id); -接受一個(gè)計(jì)時(shí)器ID(由之前兩種計(jì)時(shí)器返回)并且停止計(jì)時(shí)器回調(diào)函數(shù)的執(zhí)行。

為了理解計(jì)時(shí)器的內(nèi)部工作原理,我們首先需要了解一個(gè)非常重要的概念:計(jì)時(shí)器設(shè)定的延時(shí)是沒(méi)有保證的。因?yàn)樗性跒g覽器中執(zhí)行的JavaScript單線(xiàn)程異步事件(比如鼠標(biāo)點(diǎn)擊事件和計(jì)時(shí)器)都只有在它有空的時(shí)候才執(zhí)行。這最好通過(guò)圖片來(lái)說(shuō)明,就如下面這張圖所示:

這一張圖片里面有很多信息需要慢慢消化,但是徹底地理解這張圖片將會(huì)讓你對(duì)JavaScript異步執(zhí)行是如何工作的有一個(gè)更好的認(rèn)識(shí)。這張圖片是從一維的角度來(lái)闡述的:在垂直方向是以毫秒計(jì)的時(shí)間,藍(lán)色的塊代表了

當(dāng)前正在執(zhí)行的JavaScript代碼段。比如第一段JavaScript執(zhí)行了大概18毫秒,鼠標(biāo)點(diǎn)擊事件大概執(zhí)行了11毫秒。

由于JavaScript每次只能執(zhí)行一段代碼(基于它單線(xiàn)程的特性),所以所有這些代碼段都阻塞了其他異步事件的執(zhí)行。這就意味著,當(dāng)一件異步事件(比如鼠標(biāo)點(diǎn)擊,計(jì)時(shí)器觸發(fā)和一個(gè)XMLHttpRequest 請(qǐng)求完成)觸發(fā)的時(shí)候,這些事件的回調(diào)函數(shù)將排在執(zhí)行隊(duì)列的最后去等待執(zhí)行(排隊(duì)的方式因?yàn)g覽器不同而不同,這里只是一個(gè)簡(jiǎn)化)。

一開(kāi)始,在第一段代碼段內(nèi),兩個(gè)計(jì)時(shí)器被初始化:一個(gè)10ms的setTimeout 和一個(gè)10ms的setInterval。由于計(jì)時(shí)器在哪兒初始化就在那兒開(kāi)始計(jì)時(shí),所以實(shí)際上計(jì)時(shí)器在第一段代碼執(zhí)行完成之前就觸發(fā)了。然而,計(jì)時(shí)器的回調(diào)函數(shù)并不是立即執(zhí)行了(單線(xiàn)程限制了不能這樣做),相反的是,回調(diào)函數(shù)排在了執(zhí)行隊(duì)列的最后,等到下一個(gè)有空的時(shí)間去執(zhí)行。

此外,在第一個(gè)代碼塊內(nèi)我們看到了一個(gè)鼠標(biāo)點(diǎn)擊事件發(fā)生了。與之相關(guān)的javascript異步事件(我們不可能預(yù)測(cè)用戶(hù)會(huì)在什么時(shí)候去采取這樣的動(dòng)作,因此這個(gè)事件被視為異步的)并不會(huì)立即執(zhí)行。和計(jì)時(shí)器一樣的是,它被放到了隊(duì)列的最后去等待執(zhí)行。

在第一個(gè)代碼快執(zhí)行完成的時(shí)候,瀏覽器會(huì)立即發(fā)出這樣的詢(xún)問(wèn):誰(shuí)正在等待執(zhí)行?這個(gè)時(shí)候,鼠標(biāo)點(diǎn)擊處理程序和計(jì)時(shí)器回調(diào)函數(shù)都在等待執(zhí)行。瀏覽器選擇了其中一個(gè)(鼠標(biāo)點(diǎn)擊回調(diào)函數(shù))并且立即執(zhí)行它。為了執(zhí)行,計(jì)時(shí)器會(huì)等到下一個(gè)可能執(zhí)行的時(shí)間。

我們注意到,當(dāng)鼠標(biāo)點(diǎn)擊事件對(duì)應(yīng)的處理程序正在執(zhí)行的時(shí)候,第一個(gè)定時(shí)回調(diào)函數(shù)也要執(zhí)行了。同定時(shí)計(jì)時(shí)器一樣,它也在隊(duì)列的后面等待執(zhí)行。然而,我們可以注意到,當(dāng)定時(shí)器再一次觸發(fā)(在計(jì)時(shí)器回調(diào)函數(shù)正在執(zhí)行的時(shí)候),這一次定時(shí)器回調(diào)函數(shù)被丟棄了。如果在執(zhí)行一大塊代碼塊的時(shí)候,你把所有的定時(shí)回調(diào)函數(shù)都放在隊(duì)列的最后,結(jié)果就是一大串定時(shí)回調(diào)函數(shù)將會(huì)沒(méi)有間隔的一起執(zhí)行,直到完成。相反,在把更多定時(shí)回調(diào)函數(shù)放到隊(duì)列之前,瀏覽器會(huì)靜靜的等待,知道隊(duì)列中的所有定時(shí)回調(diào)函數(shù)都執(zhí)行完成。

事實(shí)上,我們可以看到,當(dāng)interval回調(diào)函數(shù)正在執(zhí)行的時(shí)候,interval第三次被觸發(fā)。這給我們一個(gè)很重要的信息:interval并不關(guān)心當(dāng)前誰(shuí)在執(zhí)行,它的回調(diào)函數(shù)會(huì)不加區(qū)分地進(jìn)入隊(duì)列,即使存在這個(gè)回調(diào)函數(shù)會(huì)被丟棄的可能。

最后,當(dāng)?shù)诙€(gè)定時(shí)回調(diào)函數(shù)完成執(zhí)行的時(shí)候,我們可以看到j(luò)avascript引擎已經(jīng)沒(méi)有什么需要執(zhí)行了。這意味著,瀏覽器現(xiàn)在正在等待一個(gè)新的異步事件的發(fā)生。我們可以看到在50ms的時(shí)候,定時(shí)回調(diào)函數(shù)再一次被觸發(fā)。然而,這一次,沒(méi)有其他代碼阻塞他的執(zhí)行了,所以他立即執(zhí)行了定時(shí)回調(diào)函數(shù)。

讓我們看一個(gè)例子來(lái)更好地闡述setTimeout 和setInterval的區(qū)別。

1 setTimeout(function(){
2     /* Some long block of code... */
3     setTimeout(arguments.callee, 10);
4 }, 10);
5  
6 setInterval(function(){
7     /* Some long block of code... */
8 }, 10);

第一眼看上去這兩段代碼在功能上是等價(jià)的,但事實(shí)上卻不是。值得注意的是,setTimeout 這段代碼會(huì)在每次回調(diào)函數(shù)執(zhí)行之后至少需要延時(shí)10ms再去執(zhí)行一次(可能是更多,但是不會(huì)少)。但是setInterval會(huì)每隔10ms就去嘗試執(zhí)行一次回調(diào)函數(shù),不管上一個(gè)回調(diào)函數(shù)是不是還在執(zhí)行。

從這里我們能夠?qū)W到很多,讓我們來(lái)概括一下:

javascript引擎只有一個(gè)線(xiàn)程,迫使異步事件只能加入隊(duì)列去等待執(zhí)行。

在執(zhí)行異步代碼的時(shí)候,setTimeout 和setInterval 是有著本質(zhì)區(qū)別的。

如果計(jì)時(shí)器被正在執(zhí)行的代碼阻塞了,它將會(huì)進(jìn)入隊(duì)列的尾部去等待執(zhí)行直到下一次可能執(zhí)行的時(shí)間出現(xiàn)(可能超過(guò)設(shè)定的延時(shí)時(shí)間)。

如果interval回調(diào)函數(shù)執(zhí)行需要花很長(zhǎng)時(shí)間的話(huà)(比指定的延時(shí)長(zhǎng)),interval有可能沒(méi)有延遲背靠背地執(zhí)行。

上述這一切對(duì)于理解js引擎是如果工作的無(wú)疑是很重要的知識(shí),尤其是大量的典型的異步事件發(fā)生時(shí),對(duì)于構(gòu)建一個(gè)高效的應(yīng)用代碼片段來(lái)說(shuō)是一個(gè)非常有利的基礎(chǔ)。

個(gè)人見(jiàn)解:

翻譯完成之后,感覺(jué)對(duì)于javascript異步有了新的認(rèn)識(shí),但是可能初學(xué)者看不太懂這篇文章,于是寫(xiě)了一個(gè)demo,運(yùn)行在nodejs環(huán)境下(瀏覽器不容易模擬)

 1 var startTime = new Date();
 2 
 3 //初始化計(jì)時(shí)器
 4 var start = setTimeout(function() {
 5     var end = new Date();
 6     console.log("10ms的計(jì)時(shí)器執(zhí)行完成,距離程序開(kāi)始" + (end - start) + "ms");
 7 }, 10);
 8 
 9 //模擬鼠標(biāo)點(diǎn)擊事件
10 function asyncReal(data, callback) {
11     process.nextTick(function() {
12         callback();      
13      });
14 }
15 var asyncStart = new Date();
16 asyncReal("yuanzm", function() {
17     var asyncEnd = new Date();
18     console.log("模擬鼠標(biāo)執(zhí)行事件完成,花費(fèi)時(shí)間" + (asyncEnd - asyncStart) + "ms");
19 })
20 
21 //設(shè)定定時(shí)器
22 count = 1;
23 var interval = setInterval(function() {
24     ++count;
25     if(count === 5) {
26         clearInterval(interval);
27     }
28     console.log("定時(shí)器事件");
29 },10);
30 
31 //模擬第一階段代碼執(zhí)行
32 var first = [];
33 var start = new Date();
34 for(var i = 0;i < 10000000;i++){
35     first.push(i);
36 }
37 var end = new Date();
38 console.log("第一階段代碼執(zhí)行完成,用時(shí)" + (end - start) + "ms");

運(yùn)行結(jié)果如下:

我們按照文中的原理來(lái)解釋一下:

一開(kāi)始設(shè)定的計(jì)時(shí)器并不是在10ms后立即執(zhí)行,而是被添加到了隊(duì)列后面,等到第一階段代碼執(zhí)行完成才執(zhí)行,距離開(kāi)始的時(shí)間也不是設(shè)定的10ms

鼠標(biāo)點(diǎn)擊事件同樣因?yàn)槭钱惒绞录?,添加到了?duì)列后面,等到第一階段代碼執(zhí)行完成的時(shí)候才執(zhí)行。

鼠標(biāo)點(diǎn)擊事件先于計(jì)時(shí)器事件添加到隊(duì)列后面

最后定時(shí)器才能執(zhí)行

  

鄭重聲明
本文章屬于個(gè)人原創(chuàng),如需轉(zhuǎn)載,請(qǐng)加上原文鏈接:
http://segmentfault.com/a/1190000002633108
另外同樣可以在博客園上面查看本文章:http://www.cnblogs.com/yuanzm/p/4126762.html
也歡迎Follow我的Github:https://github.com/yuanzm

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85584.html

相關(guān)文章

  • javascript時(shí)器工作原理

    摘要:說(shuō)到中的定時(shí)器,我們肯定會(huì)想到和這兩個(gè)函數(shù)。第一個(gè)回調(diào)一執(zhí)行,又開(kāi)啟了第二個(gè),這個(gè)定時(shí)器也是期望延時(shí)之后能夠執(zhí)行它的回調(diào)函數(shù)??梢杂孟旅娴膱D來(lái)概括總結(jié)上面對(duì)定時(shí)器執(zhí)行原理進(jìn)行了簡(jiǎn)要的分析,希望能夠幫助我們更深入的理解。 說(shuō)到 javascript 中的定時(shí)器,我們肯定會(huì)想到 setTimeout() 和 setInterval() 這兩個(gè)函數(shù)。本文將從 事件循環(huán)(Event Loop)...

    godlong_X 評(píng)論0 收藏0
  • Javascript時(shí)器那些事兒

    摘要:一什么是定時(shí)器提供了一些原生方法來(lái)實(shí)現(xiàn)延時(shí)去執(zhí)行某一段代碼,下面來(lái)簡(jiǎn)單介紹一下設(shè)置一個(gè)定時(shí)器,在定時(shí)器到期后執(zhí)行一次函數(shù)或代碼段定時(shí)器延遲后執(zhí)行的函數(shù)延遲后執(zhí)行的代碼字符串,不推薦使用原理類(lèi)似延遲的時(shí)間單位毫秒,默認(rèn)值為向延遲函數(shù)傳遞而外的 一、什么是定時(shí)器 JS提供了一些原生方法來(lái)實(shí)現(xiàn)延時(shí)去執(zhí)行某一段代碼,下面來(lái)簡(jiǎn)單介紹一下 setTimeout: 設(shè)置一個(gè)定時(shí)器,在定時(shí)器到期后執(zhí)行...

    Riddler 評(píng)論0 收藏0
  • 談?wù)勎覍?duì)js中定時(shí)器一點(diǎn)理解

    摘要:這兩個(gè)函數(shù)接受定時(shí)器的例如我們上面提到的兩個(gè)函數(shù)產(chǎn)生的定時(shí)器,并停止對(duì)定時(shí)器中指定函數(shù)的調(diào)用。注意,定時(shí)器雖然觸發(fā)了,但是并不會(huì)立即執(zhí)行,它只是把需要延遲執(zhí)行的函數(shù)加入了執(zhí)行隊(duì)列,在線(xiàn)程的某一個(gè)可用的時(shí)間點(diǎn),這個(gè)函數(shù)就能夠得到執(zhí)行。 擼了今年阿里、頭條和美團(tuán)的面試,我有一個(gè)重要發(fā)現(xiàn)....... javascript定時(shí)器工作原理是一個(gè)重要的基礎(chǔ)知識(shí)點(diǎn)。因?yàn)槎〞r(shí)器在單線(xiàn)程中工作,它們表...

    frontoldman 評(píng)論0 收藏0
  • 【翻譯】javascript 動(dòng)畫(huà)原理淺析

    摘要:動(dòng)畫(huà)原文通常,框架會(huì)為你處理動(dòng)畫(huà)。整個(gè)的動(dòng)畫(huà)過(guò)程被分成了很小的步驟,每一個(gè)步驟被定時(shí)器調(diào)用。因?yàn)槎〞r(shí)器的周期非常短,所以動(dòng)畫(huà)看起來(lái)是連續(xù)的。已經(jīng)過(guò)去的動(dòng)畫(huà)時(shí)間作為分子,計(jì)算每一幀通過(guò)公式。線(xiàn)性的使動(dòng)畫(huà)以固定的速度進(jìn)行。 動(dòng)畫(huà) 原文:http://javascript.info/tutori... 通常,框架會(huì)為你處理動(dòng)畫(huà)。但是,你可能想知道僅僅用javascript怎么來(lái)實(shí)現(xiàn)動(dòng)畫(huà),和可...

    Worktile 評(píng)論0 收藏0
  • 瀏覽器工作原理整理

    摘要:渲染引擎渲染引擎也稱(chēng)為瀏覽器內(nèi)核,主要時(shí)在瀏覽器窗口中顯示所請(qǐng)求的內(nèi)容,這是每個(gè)瀏覽器的核心部分。 瀏覽器的結(jié)構(gòu) 瀏覽器的主要組件包括: 用戶(hù)界面——包括地址欄、前進(jìn)/后退按鈕、書(shū)簽菜單等。除了瀏覽器主窗口顯示用戶(hù)請(qǐng)求的頁(yè)面外,其他顯示的各個(gè)部分都屬于用戶(hù)界面。 用戶(hù)界面后端——用于繪制基本的窗口小部件,比如組合框和窗口。其公開(kāi)了與web應(yīng)用無(wú)關(guān)的通用接口,而在底層使用操作系統(tǒng)的用戶(hù)...

    jzman 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<