摘要:徹底搞懂執(zhí)行機(jī)制首先我們大家都了解的是,是一門單線程語(yǔ)言,所以我們就可以得出是按照語(yǔ)句順序執(zhí)行的首先看這個(gè)顯然大家都知道結(jié)果,依次輸出,然而換一種這個(gè)時(shí)候再看代碼的順序執(zhí)行,輸出,,,。不過即使主線程為空,也是達(dá)不到的,根據(jù)標(biāo)準(zhǔn),最低是。
徹底搞懂JavaScript執(zhí)行機(jī)制
首先我們大家都了解的是,JavaScript 是一門單線程語(yǔ)言,所以我們就可以得出:
JavaScript 是按照語(yǔ)句順序執(zhí)行的
首先看:
let a = "1" console.log(a) let b = "2" console.log(b)
這個(gè)顯然大家都知道結(jié)果,依次輸出1,2
然而換一種:
setTimeout(function() { console.log(1) }) new Promise(function(resolve) { console.log(2) for(var i = 0;i< 10;i++){ i === 10 && resolve() } }).then(function() { console.log(3) }) console.log(4)
這個(gè)時(shí)候再看代碼的順序執(zhí)行,輸出1,2, 3, 4。好了放到瀏覽器運(yùn)行一下,什么?輸出居然是 2, 4, 3,1。說(shuō)好的按順序執(zhí)行呢?下面就需要去了解一下 JavaScript 的執(zhí)行機(jī)制問題了。
單線程首先JavaScript 是一門單線程的語(yǔ)言,在最新的HTML5 推出的 Web-worker,但是 JavaScript 是一個(gè)單線程的語(yǔ)言這一個(gè)核心還是沒有改變。所以,JavaScript 的多線程都是基于單線程模擬出來(lái)的。所以牢記 JavaScript 是單線程語(yǔ)言。
事件循環(huán)任務(wù)分為兩類:
同步任務(wù)
異步任務(wù)
當(dāng)我們打開頁(yè)面時(shí),頁(yè)面的渲染就是一大堆同步任務(wù),而像加載圖片和音頻資源耗時(shí)的任務(wù),就是異步任務(wù)。時(shí)間循環(huán)的主要內(nèi)容就是:
當(dāng)任務(wù)進(jìn)入執(zhí)行棧的時(shí)候,判斷是同步任務(wù)還是異步任務(wù),如果是同步任務(wù),進(jìn)入主線程進(jìn)行執(zhí)行,異步進(jìn)入 Event Table 進(jìn)行注冊(cè)函數(shù)。
當(dāng)指定的事件完成后,Event Table 將這個(gè)函數(shù)移入到事件隊(duì)列
主線程中的任務(wù)執(zhí)行完畢后,去任務(wù)隊(duì)列讀取對(duì)應(yīng)的函數(shù),進(jìn)入主線程執(zhí)行
上述的過程不斷重復(fù),也就構(gòu)成了事件循環(huán)
其中js引擎存在一個(gè)監(jiān)控進(jìn)程,不斷檢查主線程執(zhí)行棧是否為空,一旦為空,就會(huì)去時(shí)間隊(duì)列那檢查有沒有等待被調(diào)用的函數(shù)。
例如:
setTimeout( function() { console.log(1) }, 0) console.log(2)
首先 setTimeout進(jìn)入Event Table
執(zhí)行console.log(2)
setTimeout執(zhí)行的函數(shù)進(jìn)入事件隊(duì)列
主線程從事件隊(duì)列讀取函數(shù)執(zhí)行
這也就是為什么即使設(shè)置setTimeout(fn, 0)函數(shù)也不會(huì)立即執(zhí)行的原因。不過即使主線程為空,0ms也是達(dá)不到的,根據(jù)HTML標(biāo)準(zhǔn),最低是4ms。
setInterval還有一個(gè)與setTimeout類似的函數(shù),對(duì)于setInterval來(lái)說(shuō),是循環(huán)執(zhí)行。對(duì)于執(zhí)行順序來(lái)說(shuō),setInterval會(huì)每隔指定的時(shí)間將注冊(cè)的函數(shù)置入Event Queue,如果前面的任務(wù)耗時(shí)太久,那么同樣需要等待。
但是需要注意的一點(diǎn)是,對(duì)于setInterval(fn, ms)來(lái)說(shuō),他并不是每過ms執(zhí)行一次 ,而是每過 ms 會(huì)有fn進(jìn)入任務(wù)隊(duì)列。也就是說(shuō)如果setInterval 的回調(diào)函數(shù)的執(zhí)行事件如果超過延遲ms,那么就看不出來(lái)事件間隔了。
Promise 和 process.nextTick(callback)除了廣義的同步任務(wù)和異步任務(wù)之外,還有對(duì)任務(wù)更精細(xì)的劃分,分為:
macro-task(宏任務(wù)):包括整體代碼script、setTimeout、setInterval
micro-task(微任務(wù)):Promise、process.nextTick
事件循環(huán)的順序,決定js代碼的執(zhí)行順序。進(jìn)入整體代碼(宏任務(wù))后,開始第一次循環(huán)。接著執(zhí)行所有的微任務(wù)。然后再次從宏任務(wù)開始,找到其中一個(gè)任務(wù)隊(duì)列執(zhí)行完畢,再執(zhí)行所有的微任務(wù)。
用一段代碼來(lái)說(shuō)明:
setTimeout(function() { console.log("1"); }) new Promise(function(resolve) { console.log("2"); resolve() }).then(function() { console.log("3"); }) console.log("4");
這段代碼作為宏任務(wù),開始第一次循環(huán)
先遇到setTimeout,那么它的回調(diào)函數(shù)進(jìn)入到宏任務(wù)事件隊(duì)列中
遇到Promise,Promise立即執(zhí)行,輸出2,then任務(wù)進(jìn)入到微任務(wù)事件隊(duì)列中
下面遇到console,輸出4
第一個(gè)宏任務(wù)結(jié)束,看微任務(wù)事件隊(duì)列,執(zhí)行then,輸出3
第一輪循環(huán)結(jié)束,看宏任務(wù)隊(duì)列中存在setTimeout的回調(diào)函數(shù)執(zhí)行,輸出1
所有結(jié)果為:2,4,3,1
好了了解了基本的原理之后,我們來(lái)看一個(gè)更復(fù)雜的:
console.log("1"); setTimeout(function() { console.log("2"); process.nextTick(function() { console.log("3"); }) new Promise(function(resolve) { console.log("4"); resolve(); }).then(function() { console.log("5") }) }) process.nextTick(function() { console.log("6"); }) new Promise(function(resolve) { console.log("7"); resolve(); }).then(function() { console.log("8") }) setTimeout(function() { console.log("9"); process.nextTick(function() { console.log("10"); }) new Promise(function(resolve) { console.log("11"); resolve(); }).then(function() { console.log("12") }) })
不知道大家答案是什么?接下來(lái)我們來(lái)進(jìn)行分析一下:
第一輪:
首先整段代碼作為一個(gè)宏任務(wù)進(jìn)入主線程,首先遇到console.log()輸出1
遇到第一個(gè)setTimeout()進(jìn)入宏任務(wù)隊(duì)列
遇到Process.nextTick()進(jìn)入微任務(wù)隊(duì)列
然后遇到Promise,立即執(zhí)行,輸出7,then被添加到微任務(wù)隊(duì)列
遇到第二個(gè)setTimeout,進(jìn)入宏任務(wù)隊(duì)列
然后執(zhí)行兩個(gè)微任務(wù)
執(zhí)行Process.nextTick()輸出6
執(zhí)行then,輸出8
這樣第一輪循環(huán)就徹底結(jié)束了,進(jìn)行第二輪事件循環(huán),也就是第一個(gè)setTimeout
首先遇到console.log(),輸出2
遇到Process.nextTick(),進(jìn)入微任務(wù)隊(duì)列
遇到Promise立即執(zhí)行輸出4,then進(jìn)入微任務(wù)隊(duì)列
然后執(zhí)行第一個(gè)微任務(wù),輸出3
執(zhí)行then,輸出5
這樣第二輪事件循環(huán)就結(jié)束了,最后執(zhí)行第二個(gè)setTimeout,第二個(gè)setTimeout和上面原理類似,也就不重復(fù)說(shuō)明了。所以最終結(jié)果是:1,7,6,8,2,4,3,5,9,11,10,12
原文地址:傳送門
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97139.html
摘要:瀏覽器是多進(jìn)程的詳情看我上篇總結(jié)瀏覽器執(zhí)行機(jī)制的文章深入前端徹底搞懂瀏覽器運(yùn)行機(jī)制瀏覽器每打開一個(gè)標(biāo)簽頁(yè),就相當(dāng)于創(chuàng)建了一個(gè)獨(dú)立的瀏覽器進(jìn)程。執(zhí)行異步操作事件完成,回調(diào)函數(shù)進(jìn)入。主線程從讀取回調(diào)函數(shù)并執(zhí)行。 最近看了很多關(guān)于JS運(yùn)行機(jī)制的文章,每篇都獲益匪淺,但各有不同,所以在這里對(duì)這幾篇文章里說(shuō)的很精辟的地方做一個(gè)總結(jié),參考文章鏈接見最后。本文博客地址 了解進(jìn)程和線程 進(jìn)程是應(yīng)用...
摘要:瀏覽器是多進(jìn)程的詳情看我上篇總結(jié)瀏覽器執(zhí)行機(jī)制的文章深入前端徹底搞懂瀏覽器運(yùn)行機(jī)制瀏覽器每打開一個(gè)標(biāo)簽頁(yè),就相當(dāng)于創(chuàng)建了一個(gè)獨(dú)立的瀏覽器進(jìn)程。執(zhí)行異步操作事件完成,回調(diào)函數(shù)進(jìn)入。主線程從讀取回調(diào)函數(shù)并執(zhí)行。 最近看了很多關(guān)于JS運(yùn)行機(jī)制的文章,每篇都獲益匪淺,但各有不同,所以在這里對(duì)這幾篇文章里說(shuō)的很精辟的地方做一個(gè)總結(jié),參考文章鏈接見最后。本文博客地址 了解進(jìn)程和線程 進(jìn)程是應(yīng)用...
摘要:當(dāng)這些異步任務(wù)發(fā)生的時(shí)候,它們將會(huì)被放入瀏覽器的事件任務(wù)隊(duì)列中去,等到運(yùn)行時(shí)執(zhí)行線程空閑時(shí)候才會(huì)按照隊(duì)列先進(jìn)先出的原則被一一執(zhí)行,但終究還是單線程。 瀏覽器是多進(jìn)程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進(jìn)程: 瀏覽器的主進(jìn)程(負(fù)責(zé)協(xié)調(diào)、主控),只有一個(gè)。 負(fù)...
摘要:當(dāng)這些異步任務(wù)發(fā)生的時(shí)候,它們將會(huì)被放入瀏覽器的事件任務(wù)隊(duì)列中去,等到運(yùn)行時(shí)執(zhí)行線程空閑時(shí)候才會(huì)按照隊(duì)列先進(jìn)先出的原則被一一執(zhí)行,但終究還是單線程。 瀏覽器是多進(jìn)程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進(jìn)程: 瀏覽器的主進(jìn)程(負(fù)責(zé)協(xié)調(diào)、主控),只有一個(gè)。 負(fù)...
摘要:檢查宏任務(wù)隊(duì)列,發(fā)現(xiàn)有的回調(diào)函數(shù)立即執(zhí)行回調(diào)函數(shù)輸出。接著遇到它的作用是在后將回調(diào)函數(shù)放到宏任務(wù)隊(duì)列中這個(gè)任務(wù)在再下一次的事件循環(huán)中執(zhí)行。 為什么會(huì)寫這篇博文呢? 前段時(shí)間,和頭條的小伙伴聊天問頭條面試前端會(huì)問哪些問題,他稱如果是他面試的話,event-loop肯定是要問的。那天聊了蠻多,event-loop算是給我留下了很深的印象,原因很簡(jiǎn)單,因?yàn)橹拔覐奈瓷钊肓私膺^,如果是面試的時(shí)...
閱讀 2809·2023-04-25 22:15
閱讀 1843·2021-11-19 09:40
閱讀 2183·2021-09-30 09:48
閱讀 3255·2021-09-03 10:36
閱讀 2061·2021-08-30 09:48
閱讀 1906·2021-08-24 10:00
閱讀 2756·2019-08-30 15:54
閱讀 739·2019-08-30 15:54