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