javascript
彻底搞懂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
加Java架構師群獲取Java工程化、高性能及分布式、高性能、深入淺出。高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點高級進階干貨的直播免費學習權限 都是大牛帶飛 讓你少走很多的彎路的 群..號是:855801563 對了 小白勿進 最好是有開發經驗
注:加群要求
1、具有工作經驗的,面對目前流行的技術不知從何下手,需要突破技術瓶頸的可以加。
2、在公司待久了,過得很安逸,但跳槽時面試碰壁。需要在短時間內進修、跳槽拿高薪的可以加。
3、如果沒有工作經驗,但基礎非常扎實,對java工作機制,常用設計思想,常用java開發框架掌握熟練的,可以加。
4、覺得自己很牛B,一般需求都能搞定。但是所學的知識點沒有系統化,很難在技術領域繼續突破的可以加。
5.阿里Java高級大牛直播講解知識點,分享知識,多年工作經驗的梳理和總結,帶著大家全面、科學地建立自己的技術體系和技術認知!
轉載于:https://juejin.im/post/5be8108e6fb9a049ba41172d
總結
以上是生活随笔為你收集整理的彻底搞懂JavaScript执行机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: windows双机调试
- 下一篇: javascript中创建对象的几种方式