寫在前面:壓力只是暫時的,都會過去,這是我一週覺得聽到的最頓悟的一句話了吧~javascript
1.引言php
js做爲單線程的運行機制,一定有本身的運行順序,在聽了一次分享後,也好奇這種運行的機制究竟是什麼?html
js可分爲同步任務和異步任務,對於同步的任務,咱們固然知道按照順序進行執行,可是對於異步的操做,會有一個優先級的執行順序,分別爲宏任務和微任務vue
宏任務(macrotasks)和微任務(microtasks)??包含什麼?java
macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering microtasks: process.nextTick, Promises, Object.observe(廢棄), MutationObserver
在js執行時候,一個主線程裏面都會有一個事件循環(消息循環|運行循環)和事件隊列,存放各類要處理的事件信息,經過這個循環不斷處理這些事件信息或消息。web
談到這裏,很明顯知道,其實出現宏任務和微任務和瀏覽器以及js的執行機制有很大的關係。瞭解js的執行機制promise
2.javascript的執行runtime瀏覽器
這是一張javascript的執行機制圖多線程
(1) javaScript Engine,Chrome 的引擎就是 V8異步
(2) Web APIs,DOM 的操做,AJAX,Timeout 等實際上調用的都是這裏提供的
(3)Callback Queue,回調的隊列,也就是剛剛全部的 Web APIs 裏面的回調函數,實際上都是放在這裏排隊的
(4) EventLoop,事件循環,也就是剛所說的宏任務和微任務的容器
call Stack
自己就是一個調用棧(就像瀏覽器中的JavaScript解釋器),追蹤函數執行流的一種機制,當執行環境調用了多個函數時,經過調用棧,咱們能夠追蹤到哪個函數在執行,執行的函數體中又調用了哪些函數。
每調用一個函數,解釋器就會把該函數添加進調用棧並開始執行。
正在調用棧中執行的函數還調用了其它函數,那麼新函數也將會被添加進調用棧,一旦這個函數被調用,便會當即執行。
當前函數執行完畢後,解釋器將其清出調用棧,繼續執行當前執行環境下的剩餘的代碼。
當分配的調用棧空間被佔滿時,會引起「堆棧溢出」。
是存放執行的重要條件,也是由於只有一個調用棧,因此被稱爲單線程
callback quene
在js的編譯階段,將一些時間防止在執行隊列中
EventLoop 事件循環
一個做用就是將callback quene隊列裏的執行事件放在在call stack中,執行
3.事件循環
js是單線程的,執行較長的js時候,頁面會卡死,沒法響應,可是全部的操做都會被記住到另外的隊列。好比:點擊了一個元素,不會馬上的執行,可是等到js加載完畢後就會執行剛纔點擊的操做,可以知道有一個隊列記錄了全部有待執行的操做,這個隊列分爲微觀和宏觀。微觀會比宏觀執行得更快。
稱爲事件循環的緣由大多來源於源碼
while (queue.waitForMessage()) { queue.processNextMessage(); }
能夠看到入伏哦有消息就會執行,沒消息就會繼續等待
4.宏任務和微任務
是一種人們定義的執行名字,
如何區分宏任務和微任務呢?劃分的標準是什麼
console.log("開始執行1") console.log(Object.keys({a: 1})); setTimeout(() => { console.log(Object.keys({b: 2})); var promise = new Promise((resolve, reject) => { resolve(1); }); promise.then(res => { //後續增長測試 setTimeout(() => { console.log(Object.keys({e:1})) }, 0); console.log(Object.keys({c: 1})); }); }, 2000); console.log("結束執行2")
微觀任務是在當前JS調用執行完了以後馬上執行的,是同步的,在同一個調用棧裏,沒有多線程異步,如這裏包括promise.then在內的setTimeout回調裏的代碼都是在DOMTimer.Fired執行的,只是說then被放到了當前要執行的整一個異步回調函數的最後面執行。因此setTimeout 0是給主線程的消息循環任務隊列添加了一個新的task(回調),而promise.then是在當前task的V8裏的microtask插入了一個任務。那麼確定是當前正在執行的task執行完了才執行下一個task.vue的nextTick 也是一個微觀任務
let img = new Image(); img.src = 'image01.png?_=' + Date.now(); img.onload = function () { console.log('img ready'); } console.log(Object.keys({e: 1}));