十分鐘理解JavaScript引擎的執(zhí)行機制

首先该互,請牢記2點:


JS是單線程語言

JS的Event Loop是JS的執(zhí)行機制偷办。深入了解JS的執(zhí)行酝陈,就等于深入了解JS里的event loop


1.靈魂三問:JS為什么是單線程的陶耍?為什么需要異步犯戏?單線程又是如何實現(xiàn)異步的呢?

技術(shù)的出現(xiàn)娘汞,都跟現(xiàn)實世界里的應(yīng)用場景密切相關(guān)的歹茶。同樣的,我們就結(jié)合現(xiàn)實場景你弦,來回答這三個問題惊豺。

(1) JS為什么是單線程的?

JS最初被設(shè)計用在瀏覽器中禽作,那么想象一下尸昧,如果瀏覽器中的JS是多線程的。

場景描述:

那么現(xiàn)在有2個進(jìn)程旷偿,process1 process2烹俗,由于是多進(jìn)程的JS,所以他們對同一個dom萍程,同時進(jìn)行操作幢妄。process1 刪除了該dom,而process2 編輯了該dom尘喝,同時下達(dá)2個矛盾的命令磁浇,瀏覽器究竟該如何執(zhí)行呢斋陪?

這樣想朽褪,JS為什么被設(shè)計成單線程應(yīng)該就容易理解了吧置吓。

(2) JS為什么需要異步?

場景描述:

如果JS中不存在異步,只能自上而下執(zhí)行缔赠,如果上一行解析時間很長衍锚,那么下面的代碼就會被阻塞。對于用戶而言嗤堰,阻塞就意味著"卡死"戴质,這樣就導(dǎo)致了很差的用戶體驗

所以,JS中存在異步執(zhí)行踢匣。

(3) JS單線程又是如何實現(xiàn)異步的呢告匠?

既然JS是單線程的,只能在一條線程上執(zhí)行离唬,又是如何實現(xiàn)的異步呢后专?

是通過的事件循環(huán)(event loop),理解了event loop機制输莺,就理解了JS的執(zhí)行機制戚哎。


2.JS中的event loop(1)

例1,觀察它的執(zhí)行順序


console.log(1)


setTimeout(function(){

console.log(2)

},0)


console.log(3)


運行結(jié)果是:1 3 2

也就是說,setTimeout里的函數(shù)并沒有立即執(zhí)行嫂用,而是延遲了一段時間型凳,滿足一定條件后才去執(zhí)行的,這類代碼嘱函,我們叫異步代碼甘畅。

所以,這里我們首先知道了JS里的一種分類方式往弓,就是將任務(wù)分為:同步任務(wù)和異步任務(wù)橄浓。

按照這種分類方式:JS的執(zhí)行機制是:


首先判斷JS是同步還是異步,同步就進(jìn)入主進(jìn)程亮航,異步就進(jìn)入event table

異步任務(wù)在event table中注冊函數(shù)荸实,當(dāng)滿足觸發(fā)條件后,被推入event queue

同步任務(wù)進(jìn)入主線程后一直執(zhí)行缴淋,直到主線程空閑時准给,才會去event queue中查看是否有可執(zhí)行的異步任務(wù),如果有就推入主進(jìn)程中


以上三步循環(huán)執(zhí)行露氮,這就是event loop畔规。

所以上面的例子,你是否可以描述它的執(zhí)行順序了呢畴蒲?


console.log(1) 是同步任務(wù)掩宜,放入主線程里

setTimeout() 是異步任務(wù)纠吴,被放入event table, 0秒之后被推入event queue里

console.log(3 是同步任務(wù),放到主線程里


當(dāng) 1、 3在控制條被打印后,主線程去event queue(事件隊列)里查看是否有可執(zhí)行的函數(shù),執(zhí)行setTimeout里的函數(shù)。


3.JS中的event loop(2)

所以,上面關(guān)于event loop就是我對JS執(zhí)行機制的理解,直到我遇到了下面這段代碼。

例2:


setTimeout(function(){

console.log('定時器開始啦')

});


new Promise(function(resolve){

console.log('馬上執(zhí)行for循環(huán)啦');

for(var i = 0; i < 10000; i++){

i == 99 && resolve();

}

}).then(function(){

console.log('執(zhí)行then函數(shù)啦')

});


console.log('代碼執(zhí)行結(jié)束');


嘗試按照糕殉,上文我們剛學(xué)到的JS執(zhí)行機制去分析:


setTimeout 是異步任務(wù)殖告,被放到event table

new Promise 是同步任務(wù)阿蝶,被放到主進(jìn)程里,直接執(zhí)行打印 console.log('馬上執(zhí)行for循環(huán)啦')

.then 里的函數(shù)是異步任務(wù)黄绩,被放到event table

console.log('代碼執(zhí)行結(jié)束') 是同步代碼羡洁,被放到主進(jìn)程里,直接執(zhí)行


所以爽丹,結(jié)果是: 馬上執(zhí)行for循環(huán)啦---代碼執(zhí)行結(jié)束---定時器開始啦---執(zhí)行then函數(shù)啦嗎?

親自執(zhí)行后筑煮,結(jié)果居然不是這樣,而是: 馬上執(zhí)行for循環(huán)啦---代碼執(zhí)行結(jié)束---執(zhí)行then函數(shù)啦---定時器開始啦

那么粤蝎,難道是異步任務(wù)的執(zhí)行順序真仲,不是前后順序,而是另有規(guī)定初澎?事實上秸应,按照異步和同步的劃分方式,并不準(zhǔn)確碑宴。

而準(zhǔn)確的劃分方式是:


macro-task(宏任務(wù)):包括整體代碼script软啼,setTimeout,setInterval

micro-task(微任務(wù)):Promise延柠,process.nextTick




按照這種分類方式祸挪,JS的執(zhí)行機制是:


執(zhí)行一個宏任務(wù),過程中如果遇到微任務(wù)贞间,就將其放到微任務(wù)的“事件隊列”里

當(dāng)前宏任務(wù)執(zhí)行完成后匕积,會查看微任務(wù)的“事件隊列”,并將里面全部的微任務(wù)依次執(zhí)行完

重復(fù)以上2步驟榜跌,結(jié)合event loop(1) event loop(2)闪唆,就是更為準(zhǔn)確的JS執(zhí)行機制了


嘗試按照剛學(xué)的執(zhí)行機制,去分析例2:


首先執(zhí)行script下的宏任務(wù)钓葫,遇到setTimeout,將其放到宏任務(wù)的“隊列”里

遇到 new Promise直接執(zhí)行悄蕾,打印"馬上執(zhí)行for循環(huán)啦"

遇到then方法,是微任務(wù),將其放到微任務(wù)的“隊列”里帆调。

打印 "代碼執(zhí)行結(jié)束"

本輪宏任務(wù)執(zhí)行完畢奠骄,查看本輪的微任務(wù),發(fā)現(xiàn)有一個then方法里的函數(shù)番刊,打印"執(zhí)行then函數(shù)啦"

到此,本輪的event loop 全部完成含鳞。

下一輪的循環(huán)里,先執(zhí)行一個宏任務(wù)芹务,發(fā)現(xiàn)宏任務(wù)的“隊列”里有一個setTimeout里的函數(shù),執(zhí)行打印"定時器開始啦"


所以最后的執(zhí)行順序是: 馬上執(zhí)行for循環(huán)啦---代碼執(zhí)行結(jié)束---執(zhí)行then函數(shù)啦---定時器開始啦


4.談?wù)剆etTimeout

這段setTimeout代碼什么意思? 我們一般說: 3秒后,會執(zhí)行setTimeout里的那個函數(shù)

setTimeout(function(){ console.log('執(zhí)行了') },3000)

但是這種說并不嚴(yán)謹(jǐn)蝉绷,準(zhǔn)確的解釋是:3秒后,setTimeout里的函數(shù)被會推入event queue枣抱,而event queue(事件隊列)里的任務(wù)熔吗,只有在主線程空閑時才會執(zhí)行。

所以只有滿足 (1)3秒后 (2)主線程空閑佳晶,同時滿足時桅狠,才會3秒后執(zhí)行該函數(shù)

如果主線程執(zhí)行內(nèi)容很多,執(zhí)行時間超過3秒轿秧,比如執(zhí)行了10秒中跌,那么這個函數(shù)只能10秒后執(zhí)行了。


編輯:千鋒HTML5

作者: ziwei3749

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末菇篡,一起剝皮案震驚了整個濱河市漩符,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逸贾,老刑警劉巖陨仅,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異铝侵,居然都是意外死亡灼伤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門咪鲜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狐赡,“玉大人,你說我怎么就攤上這事疟丙∮敝叮” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵享郊,是天一觀的道長览祖。 經(jīng)常有香客問我,道長炊琉,這世上最難降的妖魔是什么展蒂? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任又活,我火速辦了婚禮,結(jié)果婚禮上锰悼,老公的妹妹穿的比我還像新娘柳骄。我一直安慰自己,他們只是感情好箕般,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布耐薯。 她就那樣靜靜地躺著,像睡著了一般丝里。 火紅的嫁衣襯著肌膚如雪曲初。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天丙者,我揣著相機與錄音复斥,去河邊找鬼营密。 笑死械媒,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的评汰。 我是一名探鬼主播纷捞,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼被去!你這毒婦竟也來了主儡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惨缆,失蹤者是張志新(化名)和其女友劉穎糜值,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坯墨,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡寂汇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捣染。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骄瓣。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耍攘,靈堂內(nèi)的尸體忽然破棺而出榕栏,到底是詐尸還是另有隱情,我是刑警寧澤蕾各,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布扒磁,位于F島的核電站,受9級特大地震影響式曲,放射性物質(zhì)發(fā)生泄漏妨托。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望始鱼。 院中可真熱鬧仔掸,春花似錦、人聲如沸医清。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽会烙。三九已至负懦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柏腻,已是汗流浹背纸厉。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留五嫂,地道東北人颗品。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像沃缘,于是被迫代替她去往敵國和親躯枢。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容