前幾天在理解node的事件環機制中引起了我對瀏覽器裏Event Loop的好奇。咱們都知道javascript是單線程的,任務是須要一個一個按順序執行的,若是javascript有兩個線程,一個爲DOM增長樣式,一個卻要刪除DOM,這樣豈不是就會很混亂。單線程能夠節約內存,可是必須等待前一個任務完成後才能執行下一個任務。接下來理解瀏覽器中的Event Loop,先看一張圖:javascript
heap(堆)是用戶主動請求而劃分出來的內存區域,好比你new Object(),就是將一個對象存入堆中,能夠理解爲heap存對象。
stack(棧)是因爲函數運行而臨時佔用的內存區域,函數都存放在棧裏。html
在上一張圖中:
一、全部同步任務都在主線程上執行,造成一個執行棧;
二、只要異步任務有了運行結果,就在任務隊列(task queue)(隊列是一個先進先出的數據結構,而棧是一個先進後出的數據結構)之中放置一個事件;
三、一旦執行棧中的全部同步任務執行完畢,系統就會讀取任務隊列,又將隊列中的事件放到stack中依次執行,就是執行異步任務中的回調函數。這個過程是循環不斷的,這就是Event Loop(事件循環);vue
在上張圖中,咱們看到還有宏任務(MacroTask)和微任務(MicroTask)之分。
宏任務(MacroTask)
setTimeout setInterval
微任務(MicroTask)
Promise.then MessageChannel微任務(vue中nextTick實現原理)
同步任務先執行,遇到微任務 就將微任務放入執行棧 微任務會先執行,再執行宏任務,java
先看一下圖(我的理解)node
console.log(1); setTimeout(function(){ console.log(2); new Promise(function(resolve,reject){ console.log('promise'); resolve(); }).then(res=>{ console.log('promise.then'); }) }); setTimeout(function(){ console.log(4); }) console.log(5);
將這行代碼放入瀏覽器控制檯中promise
分析一下:
執行棧中同步任務先執行,先走console.log(1)和console.log(5);
接着是遇到setTimeout將它們的回調函數放入MacroTask(宏任務隊列);
而後將任務隊列中的回調函數依次放入主執行棧中執行,console.log(2),接着promise是當即執行,promise.then是微任務放入MicroTask中先執行;
最後執行第二個setTimeout的回調函數console.log(4);瀏覽器
瀏覽器中的Event Loop和node的Event Loop有所不一樣,先來看看區別:數據結構
在node環境裏,執行棧會先執行完當前任務隊列,也就是兩個setTimeout中的回調函數執行完纔會去執行咱們的微任務隊列,也就是promise.then是最後執行的,是否是很奇怪。異步
請看下面的示意圖(做者 @BusyRich)。函數
這裏須要注意一下,node新加了一個微任務( process.nextTick)和一個宏任務( setImmediate)
簡單的來講,就是node在處理一個執行隊列的時候無論怎樣都會先執行完當前隊列,而後再清空微任務隊列,再去執行下一個隊列。
廢話很少說,直接上圖(我的理解)。
這裏應該都明白了吧,最後注意一下,微任務中process.nextTick比promise.then快
水平不足,歡迎各位指正。