javascript
[ Javascript ] JavaScript中的定时器(Timer) 是怎样工作的!
作為入門者來說。了解JavaScript中timer的工作方式是非常重要的。通常它們的表現(xiàn)行為并非那么地直觀,而這是由于它們都處在一個(gè)單一線程中。讓我們先來看一看三個(gè)用來創(chuàng)建以及操作timer的函數(shù)。
var id = setTimeout(fn, delay);- 初始化一個(gè)單一的timer,這個(gè)timer將會(huì)在一定延時(shí)后去調(diào)用指定的函數(shù)。這個(gè)函數(shù)(setTimeout)將返回一個(gè)唯一的ID,我們能夠通過這個(gè)ID來取消timer。
var id = setInterval(fn, delay);- 與setTimeout類似,僅僅只是它會(huì)持續(xù)地調(diào)用指定的函數(shù)(每次都有一個(gè)延時(shí)),直到timer被取消為止。 clearInterval(id);, clearTimeout(id);- 接受一個(gè)timer的ID(由上述的兩個(gè)函數(shù)返回的),而且停止timer的回調(diào)事件。要弄明確這個(gè)定時(shí)器內(nèi)部是怎么工作的,有一個(gè)非常重要的概念須要被提出來:
1 定時(shí)器延遲是不準(zhǔn)確的(guaranteed).由于全部的javascript 瀏覽器代碼僅僅有一個(gè)單線程運(yùn)行,而且那些異步事件(如鼠標(biāo)點(diǎn)擊事件,和定時(shí)器)僅僅會(huì)在出現(xiàn)線程空暇的時(shí)候去會(huì)運(yùn)行。這有一個(gè)圖表演示。例如以下:
這里有非常多信息在這個(gè)圖中須要去理解??墒侨焕斫馑蟆D銜?huì)對(duì)javascript中異步機(jī)制有一個(gè)清楚的認(rèn)識(shí)。
這個(gè)圖是一維的:
垂直方向我們用毫秒單位來標(biāo)記這個(gè)時(shí)間。這個(gè)藍(lán)色的方塊代表這個(gè)正在被運(yùn)行的javascript代碼。比如,這第一個(gè)被運(yùn)行的javascript代碼大約花了18毫秒,這個(gè)鼠標(biāo)事件塊大約花費(fèi)了11毫秒,等等。
由于javascript 引擎永遠(yuǎn)僅僅會(huì)執(zhí)行一個(gè)片段的代碼在同一個(gè)時(shí)間(由于這個(gè)單線程機(jī)制),那么這時(shí)每個(gè)代碼塊將會(huì)堵塞(blocking)別的異步事件的執(zhí)行。
這意味著當(dāng)一個(gè)異步事件被調(diào)用(比如當(dāng)一個(gè)鼠標(biāo)點(diǎn)擊,一個(gè)定時(shí)器觸發(fā)firing,或者一個(gè)xmlhttprequest 過程完畢),它將會(huì)被增加到隊(duì)里。并延遲運(yùn)行(至于詳細(xì)怎樣被入到隊(duì)列中,不同的瀏覽器有不同的實(shí)現(xiàn)。我們這里僅僅考慮簡(jiǎn)單的情況)
從一開始,在第一個(gè)javasript中,有兩個(gè)定時(shí)器被初始化了: 一個(gè)10 毫秒的 setTimeout時(shí)間和一個(gè)10 毫秒的setInterval事件(這里注意,只不過初始化,亦或叫作定義)。
由于這個(gè)定時(shí)器開始的時(shí)間和位置。導(dǎo)致它們?cè)诘谝粋€(gè)javascript塊完畢前就已經(jīng)真正被調(diào)用(這里的調(diào)用,并不是直接運(yùn)行,這里須要注意,能夠理解為僅僅是準(zhǔn)備調(diào)用,把該回調(diào)方法增加到隊(duì)列)了。
注意,不管怎么樣(however)。定時(shí)器都不會(huì)立馬運(yùn)行(由于線程沒有空暇的原因,它沒辦法直接運(yùn)行)。
相反。這個(gè)被延遲的方法會(huì)被增加到隊(duì)列中,在某個(gè)能夠運(yùn)行的時(shí)刻(線程空暇的時(shí)刻)運(yùn)行。
另外一點(diǎn),在第一個(gè)javascript塊中。我們能夠看到另一個(gè)鼠標(biāo)事件被觸發(fā)了。這個(gè)javascript 回調(diào)方法被關(guān)聯(lián)到一個(gè)異步事件 (沒人知道用戶什么時(shí)候做這個(gè)動(dòng)作。所以它被覺得是異步的),這個(gè)異步事件也不會(huì)立馬運(yùn)行,和上面的定時(shí)器一樣。也會(huì)被增加到隊(duì)列中。
在第一個(gè)javascript 塊運(yùn)行結(jié)束之后,javascript 引擎就會(huì)立馬問一個(gè)問題: 還有什么在等待被運(yùn)行的代碼么? 那么這個(gè)時(shí)間,有一個(gè)鼠標(biāo)事件回調(diào)和定時(shí)器回調(diào)同一時(shí)候在等待。這個(gè)瀏覽器立即挑選一個(gè)(從圖中看。是鼠標(biāo)事件回調(diào))立馬運(yùn)行。這個(gè)定時(shí)器繼續(xù)等待,直到下一個(gè)可能的時(shí)刻。
注意一點(diǎn):在這個(gè)這個(gè)鼠標(biāo)事件處理函數(shù)正在被運(yùn)行的同一時(shí)候,第一個(gè)interval 回調(diào)函數(shù)也會(huì)調(diào)用。
正如前面提到的定時(shí)器一樣,它的回調(diào)方法會(huì)被增加到隊(duì)列中。
然而。注意當(dāng)這個(gè)interval再一次被調(diào)用(這個(gè)時(shí)候這個(gè)定時(shí)器的回調(diào)方法正在被運(yùn)行)。那么這個(gè)時(shí)候。這個(gè)interval 的回調(diào)方法將會(huì)被刪除(drop)。
假設(shè)因?yàn)橹骶€程須要運(yùn)行非常長(zhǎng)時(shí)間的代碼塊,導(dǎo)致你在隊(duì)列中增加了非常多個(gè)回調(diào)方法,那么當(dāng)這個(gè)主線程結(jié)束之后,一連串的回調(diào)函數(shù)連續(xù)運(yùn)行沒有間隔,直到結(jié)束。比較好的做法,是臨時(shí)讓瀏覽器歇息等待一會(huì)。讓隊(duì)列中沒有Interval回調(diào)。
我們?cè)诳吹揭恍┣闆r:在第三個(gè)interval 回調(diào)方法觸發(fā)的時(shí)候。inteval自身正在運(yùn)行(這里應(yīng)該是下在運(yùn)行第二個(gè)interval沒有結(jié)束)。這里給我們展示了一個(gè)重要的信息:
interval 不會(huì)去關(guān)心當(dāng)前的線程如今運(yùn)行什么,它們會(huì)把自己的回調(diào)方法增加到隊(duì)列中在不論什么情況下,即使它會(huì)讓兩個(gè)間隔的回調(diào)方法之間的時(shí)間降低。
最后,在第二個(gè)interval(圖中應(yīng)該是第三個(gè),這里應(yīng)為中間有一個(gè)被drop掉了)被 運(yùn)行完之后,javasript引擎中已經(jīng)沒有東西能夠用來運(yùn)行了。
這也就是說。瀏覽器如今正在等一個(gè)新的異步事件須要去觸發(fā)(occur)。在第50毫秒的時(shí)候,再一次觸發(fā)了inteval回調(diào)。
這個(gè)時(shí)候。已經(jīng)沒有東西去堵塞它的運(yùn)行。所以它增加到隊(duì)列中之后就立馬運(yùn)行了。
接下來,讓我們看一個(gè)樣例更好的理解setTimeout與setInterval的差別:
setTimeout(function(){/* Some long block of code... */setTimeout(arguments.callee, 10);}, 10);setInterval(function(){/* Some long block of code... */}, 10);這兩段代碼可能在功能的實(shí)現(xiàn)上很的相似。不經(jīng)意一看,他們是全然一樣的。
尤其是這個(gè)setTimeout代碼會(huì)在上一個(gè)回調(diào)函數(shù)運(yùn)行之后至少隔10毫秒再運(yùn)行一次回調(diào)方法(它可能會(huì)超過10毫秒,但不會(huì)少于10毫秒)??墒莝etInteval 卻會(huì)嘗試10毫秒就運(yùn)行一個(gè)回調(diào)函數(shù),不會(huì)去管上一個(gè)回調(diào)是什么時(shí)候運(yùn)行的。
These two pieces of code may appear to be functionally equivalent, at first glance, but they are not. Notably the setTimeout code will always have at least a 10ms delay after the previous callback execution (it may end up being more, but never less) whereas the setInterval will attempt to execute a callback every 10ms regardless of when the last callback was executed.
這里有一些東西是我們從這里學(xué)到的,做一個(gè)總結(jié):
1 javascript引擎只唯獨(dú)一個(gè)單線程,正在運(yùn)行的異步事件會(huì)增加到隊(duì)列等待。
2 setTimeout與setInterval 是運(yùn)行異步回調(diào)方法從根本上不一樣的。
3 假設(shè)一個(gè)須要馬上運(yùn)行的定時(shí)器被堵塞了。它將被延遲運(yùn)行。知道下一次線程空暇(那么被延遲的時(shí)間會(huì)超過定時(shí)器定義的時(shí)間)
4 interval 可能會(huì)沒有延遲的連續(xù)運(yùn)行回調(diào)方法,假設(shè)主線程了運(yùn)行一個(gè)足夠長(zhǎng)的代碼(比定時(shí)的延遲長(zhǎng))
全部的這些都是很重要的知識(shí)對(duì)于了解javascript引擎是怎樣工作的。特別是對(duì)于大數(shù)量的回調(diào)事件發(fā)生的時(shí)候,為我們建立更好的應(yīng)用代碼建立好的基礎(chǔ)。
----------------------------------------------------------------------------------------------------
原文出自jQuery的作者John Resig。
地址:http://ejohn.org/blog/how-javascript-timers-work/#postcomment
轉(zhuǎn)載于:https://www.cnblogs.com/claireyuancy/p/6956876.html
總結(jié)
以上是生活随笔為你收集整理的[ Javascript ] JavaScript中的定时器(Timer) 是怎样工作的!的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: handsontable 方法汇总
- 下一篇: Android 软键盘自动弹出和关闭