摘要:這兩個(gè)函數(shù)接受定時(shí)器的例如我們上面提到的兩個(gè)函數(shù)產(chǎn)生的定時(shí)器,并停止對(duì)定時(shí)器中指定函數(shù)的調(diào)用。注意,定時(shí)器雖然觸發(fā)了,但是并不會(huì)立即執(zhí)行,它只是把需要延遲執(zhí)行的函數(shù)加入了執(zhí)行隊(duì)列,在線程的某一個(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)出的行為很直觀。我們?cè)撊绾蝿?chuàng)建和維護(hù)定時(shí)器呢?要從如下三個(gè)函數(shù)(都是定義在全局作用域,在瀏覽器中就是window的方法)說(shuō)起:
var id=setTimeout(fn,delay);
-初始化一個(gè)只執(zhí)行一次的定時(shí)器,這個(gè)定時(shí)器會(huì)在指定的時(shí)間延遲delay之后調(diào)用函數(shù)fn,該setTimeout函數(shù)返回定時(shí)器的唯一id,我們可以通過(guò)這個(gè)id來(lái)取消定時(shí)器的執(zhí)行。
var id=setInvertal(fn,delay);
-與setTimeout類(lèi)似,只是它會(huì)以delay為周期,反復(fù)調(diào)用函數(shù)fn,直到我們通過(guò)id取消該定時(shí)器。
clearInterval(id);clearTimeout(id);
-這兩個(gè)函數(shù)接受定時(shí)器的id(例如我們上面提到的兩個(gè)函數(shù)產(chǎn)生的定時(shí)器id),并停止對(duì)定時(shí)器中指定函數(shù)的調(diào)用。
要深入理解定時(shí)器工作原理,我們需要探索一個(gè)重要的概念:定時(shí)器指定的延遲時(shí)間并不能得到保證。在瀏覽器中,因?yàn)樗械膉avascript代碼都運(yùn)行在單一線程之中,異步事件(如鼠標(biāo)點(diǎn)擊,定時(shí)器)只有在他們被觸發(fā)的時(shí)候他們的回調(diào)才有機(jī)會(huì)得以執(zhí)行。我們可以用下圖說(shuō)明:
圖中包含大量的信息,吸收并理解這些信息,能幫助我們領(lǐng)悟“異步的javascript代碼是如何工作的”。這個(gè)圖是一維的,垂直方向是時(shí)間,以毫秒為單位。藍(lán)色的盒子代表正在執(zhí)行的javascript代碼所占時(shí)間片段。例如 第一個(gè)javascript塊執(zhí)行時(shí)間約18ms,第二個(gè)鼠標(biāo)點(diǎn)擊塊執(zhí)行了約11ms,其他塊類(lèi)似。
因?yàn)閱尉€程的緣故,在同一時(shí)間只能執(zhí)行一條javascript代碼,每一個(gè)代碼塊(藍(lán)色盒子)都會(huì)阻塞其他異步事件的執(zhí)行。這就意味著,當(dāng)一個(gè)異步事件發(fā)生的時(shí)候(例如鼠標(biāo)點(diǎn)擊,定時(shí)器觸發(fā),一個(gè)XMLHttpRequest 請(qǐng)求完成),它進(jìn)入了代碼的執(zhí)行隊(duì)列,執(zhí)行線程空閑時(shí)會(huì)依照該執(zhí)行隊(duì)列中順序依次執(zhí)行代碼。(如何將異步事件加入隊(duì)列,不同瀏覽器,他們的實(shí)現(xiàn)可能有所差異,所以這里我們將其簡(jiǎn)單化)。
開(kāi)始的時(shí)候,在Javascript代碼塊(第一個(gè)盒子),初始化了兩個(gè)定時(shí)器,一個(gè)10ms延遲的setTimeout 和10ms的setInterval。這些定時(shí)器可能會(huì)在我們第一個(gè)代碼塊執(zhí)行結(jié)束之前就觸發(fā),這取決于定時(shí)器在第一個(gè)代碼塊中啟動(dòng)的位置和時(shí)間。注意,定時(shí)器雖然觸發(fā)了,但是并不會(huì)立即執(zhí)行,它只是把需要延遲執(zhí)行的函數(shù)加入了執(zhí)行隊(duì)列,在線程的某一個(gè)可用的時(shí)間點(diǎn),這個(gè)函數(shù)就能夠得到執(zhí)行。
當(dāng)?shù)谝粋€(gè)Javascript代碼初始化塊執(zhí)行結(jié)束,瀏覽器立即提出一個(gè)問(wèn)題:誰(shuí)在等待著被執(zhí)行? 在這個(gè)案例中鼠標(biāo)點(diǎn)擊時(shí)間的處理程序和一個(gè)定時(shí)器(setTimeout)都在等待。瀏覽器選擇一個(gè)并執(zhí)行(這里是鼠標(biāo)點(diǎn)擊事件的處理程序)。定時(shí)器就需要等待下一個(gè)可用時(shí)間來(lái)執(zhí)行。
需要注意的是當(dāng)鼠標(biāo)點(diǎn)擊事件處理程序執(zhí)行的時(shí)候,第一個(gè)interval定時(shí)器觸發(fā)了。和timeout定時(shí)器一樣,他的回調(diào)函數(shù)被加入了執(zhí)行隊(duì)列,等待執(zhí)行。然而,還需要注意到當(dāng)interval定時(shí)器再次觸發(fā),這個(gè)時(shí)候timeout定時(shí)器的回調(diào)函數(shù)正在執(zhí)行,此時(shí)這個(gè)interval的觸發(fā)被放棄了。假想(瀏覽器不這樣做),在一個(gè)占用時(shí)間很多的初始化定時(shí)器的代碼塊中,所有的interval觸發(fā)都把回調(diào)加入執(zhí)行隊(duì)列,當(dāng)初始化代碼塊結(jié)束后,執(zhí)行隊(duì)列中已經(jīng)累加了大量的定時(shí)器回調(diào)函數(shù),結(jié)果就會(huì)出現(xiàn)大量的interval回調(diào)函數(shù)無(wú)間隔的執(zhí)行,直到該執(zhí)行隊(duì)列清空。所以瀏覽器在講一個(gè)interval回調(diào)加入執(zhí)行隊(duì)列前,會(huì)檢查執(zhí)行隊(duì)列,如果其中存在尚未執(zhí)行的interval回調(diào)那么就等待,直到當(dāng)前執(zhí)行隊(duì)列中沒(méi)有相應(yīng)interval的回調(diào)以后才會(huì)繼續(xù)入隊(duì)interval回調(diào)。
事實(shí)上,如圖,我們看見(jiàn)在第一個(gè)Interval的回調(diào)執(zhí)行的時(shí)候(之前進(jìn)入執(zhí)行隊(duì)列),第三個(gè)interval觸發(fā)了,這想我們展示一個(gè)重要的現(xiàn)象:Interval不關(guān)心當(dāng)前正在執(zhí)行的代碼,他們會(huì)不加選擇的添加回調(diào)到執(zhí)行隊(duì)列,盡管這意味著兩個(gè)interval回調(diào)函數(shù)執(zhí)行的時(shí)間間隔被犧牲。這里第一個(gè)interval回調(diào)執(zhí)行結(jié)束后,緊跟著第三個(gè)interval的回調(diào)馬上得到執(zhí)行,中間沒(méi)有印象中應(yīng)該有的10ms間隔。
最終,在第三個(gè)interval的回調(diào)執(zhí)行結(jié)束后,我們看見(jiàn)執(zhí)行隊(duì)列中沒(méi)有等待javascript引擎執(zhí)行的代碼,這就意味著,瀏覽器現(xiàn)在等待新的異步事件的發(fā)生,在50ms的刻度處interval再次觸發(fā),此時(shí)沒(méi)有什么會(huì)阻塞javascript引擎,這個(gè)interval回調(diào)會(huì)立即執(zhí)行。
讓我們看一個(gè)例子來(lái)闡明,setInterval和setTimeout的不同,
setTimeout(function(){ /* Some long block of code... */ setTimeout(arguments.callee, 10); }, 10); setInterval(function(){ /* Some long block of code... */ }, 10);
看第一眼,會(huì)覺(jué)得這兩段代碼功能相同,實(shí)際上,他們是不同的。
需要注意到,setTimeout的回調(diào)函數(shù)的執(zhí)行總是保證了至少10ms的間隔(與上一個(gè)回調(diào)的執(zhí)行相比,實(shí)際執(zhí)行時(shí),這個(gè)間隔可能變長(zhǎng),但是不可能更少),但是setInterval會(huì)嘗試每隔10ms執(zhí)行一次回調(diào),不管上一個(gè)回調(diào)函數(shù)時(shí)候已經(jīng)執(zhí)行完畢。(很多類(lèi)庫(kù)的動(dòng)畫(huà)都是使用的setTimeout實(shí)現(xiàn))
這里我們學(xué)到很多,總結(jié)一下:
javascript引擎是單線程的,會(huì)迫使異步事件進(jìn)入執(zhí)行隊(duì)列,等待執(zhí)行。
setTimeout和setInterval在執(zhí)行異步代碼時(shí)從根本上是有所不同的。
如果一個(gè)定時(shí)器事件被阻塞,使得它不能立即執(zhí)行,那么它會(huì)被延遲,直到下一個(gè)可能的時(shí)間點(diǎn),才被執(zhí)行(這可能比你指定的delay時(shí)間要長(zhǎng))
Interval的回調(diào)有可能‘背靠背’無(wú)間隔的執(zhí)行,這種情況是說(shuō)interval的回調(diào)函數(shù)的執(zhí)行時(shí)間比你指定的delay時(shí)間還要長(zhǎng)
這些都是構(gòu)建javascript應(yīng)用程序非常重要的知識(shí)。了解javascript Engine是如何工作的,特別存在大量的異步事件發(fā)生,為構(gòu)建高級(jí)應(yīng)用程序代碼打下基礎(chǔ)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/106489.html
摘要:深入理解引擎的執(zhí)行機(jī)制靈魂三問(wèn)為什么是單線程的為什么需要異步單線程又是如何實(shí)現(xiàn)異步的呢中的中的說(shuō)說(shuō)首先請(qǐng)牢記點(diǎn)是單線程語(yǔ)言的是的執(zhí)行機(jī)制。 深入理解JS引擎的執(zhí)行機(jī)制 1.靈魂三問(wèn) : JS為什么是單線程的? 為什么需要異步? 單線程又是如何實(shí)現(xiàn)異步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.說(shuō)說(shuō)setTimeout 首先,請(qǐng)牢記2...
showImg(https://segmentfault.com/img/remote/1460000007103938?w=391&h=247); 文章最初發(fā)表于我的個(gè)人博客非典型性程序猿 對(duì)于剛接觸JAVA或者其他面向?qū)ο缶幊陶Z(yǔ)言的朋友們來(lái)說(shuō),可能一開(kāi)始都很難理解面向?qū)ο蟮母拍钜约邦?lèi)和對(duì)象的關(guān)系。筆者曾經(jīng)帶過(guò)一個(gè)短期培訓(xùn)班教授java入門(mén)基礎(chǔ),在最后結(jié)束課程的時(shí)候,還有很多同學(xué)不太理解面向?qū)ο?..
摘要:深入理解引擎的執(zhí)行機(jī)制最近在反省,很多知識(shí)都是只會(huì)用,不理解底層的知識(shí)。在閱讀之前,請(qǐng)先記住兩點(diǎn)是單線程語(yǔ)言的是的執(zhí)行機(jī)制。所以,是存在異步執(zhí)行的,比如單線程是怎么實(shí)現(xiàn)異步的場(chǎng)景描述通過(guò)事件循環(huán),所以說(shuō),理解了機(jī)制,也就理解了的執(zhí)行機(jī)制啦。 深入理解js引擎的執(zhí)行機(jī)制 最近在反省,很多知識(shí)都是只會(huì)用,不理解底層的知識(shí)。所以在開(kāi)發(fā)過(guò)程中遇到一些奇怪的比較難解決的bug,在思考的時(shí)候就會(huì)收...
摘要:同時(shí),創(chuàng)建的子類(lèi)有幾個(gè)固定字段,分別是初始化函數(shù)原型初始化函數(shù)對(duì)象通過(guò)這個(gè)函數(shù),把基類(lèi)和子類(lèi)的函數(shù)合并執(zhí)行,這樣解決了基類(lèi)構(gòu)造函數(shù)無(wú)法執(zhí)行的問(wèn)題。二是構(gòu)造函數(shù)可能不止會(huì)操作,還可能會(huì)修改全局的某些狀態(tài)比如計(jì)數(shù)器。 綜述 在 ES6 之前,ES5 實(shí)現(xiàn)面向?qū)ο笫谴蠹医?jīng)常討論的問(wèn)題,趁著 ES6 還沒(méi)進(jìn)入瀏覽器,借我自己的一段腳本,跟大家討論一下 js 面向?qū)ο蟮囊恍┘?xì)節(jié)問(wèn)題,歡迎留言指教...
摘要:使用簡(jiǎn)記后端掘金全稱(chēng)為即消息隊(duì)列。優(yōu)測(cè)優(yōu)社區(qū)干貨精選老司機(jī)亂談編輯器之神掘金前言是一種信仰,我自從年有了這個(gè)信仰,已經(jīng)個(gè)年頭了。 PHP 程序員進(jìn)階學(xué)習(xí)書(shū)籍參考指南 - 后端 - 掘金PHP程序員進(jìn)階學(xué)習(xí)書(shū)籍參考指南 @heiyeluren lastmodify: 2016/2/18 ... 當(dāng)我們?cè)谡務(wù)撉岸思用軙r(shí),我們?cè)谡勑┦裁?- 前端 - 掘金潘建旭,豈安科技(www.bigse...
閱讀 2511·2023-04-25 22:09
閱讀 1023·2021-11-17 17:01
閱讀 1556·2021-09-04 16:45
閱讀 2619·2021-08-03 14:02
閱讀 816·2019-08-29 17:11
閱讀 3254·2019-08-29 12:23
閱讀 1089·2019-08-29 11:10
閱讀 3281·2019-08-26 13:48