JS事件循環機制(event loop),什麼是宏任務、微任務

JavaScript 這門語言跟其他語言有區別,如果你看Jquery,Vue,React,Angular源碼的時候,如果你沒有理解事件機制很難理解裡面的一些內容。

JAVA ,Python是多線程語言(Python可是說是偽多線程)代碼的寫法跟JavaScript有太大的區別了,寫慣多線程語言的代碼,寫JavaScript要有一定的適應期。

現在HTML5,ES6,ES7,ES8,ES9有很大的改進很多時候不用寫這種回調的代碼了JavaScript有點像Python了現在。

先不要理什麼是任務,看一段代碼;

for(var i=0;i<5;i++ ){
setTimeout(function(){
console.log(i)
},0)
}
// 請問打印出是什麼
答案 5

js 是就是這麼奇葩,每個前端開發者都會被這個異步回調搞的頭暈腦脹。

下面這段代碼打印順序是什麼呢?

console.log('start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('end');
JS事件循環機制(event loop),什麼是宏任務、微任務

答案是:

  1. start
  2. end
  3. promise1
  4. promise2
  5. setTimeout

其實有些瀏覽器是不支持Promise 答案會有所不同。但是那些不是本篇文章考慮的內容。

為什麼會出現這樣的順序呢?

要想知道為啥會這樣那就要理解JavaScript的宏任務和微任務。

js執行的時候也就是每個線程(不知道沒有關係)都有一個事件隊列,這個事件隊列是等所有的主線程執行(原代碼的順序)完成後,再執行事件隊列執行的走的是事件循環,而且遵循事件循環。

這些宏任務源保證了在本任務源內的順序。但是瀏覽器每次都會選擇一個源中的一個宏任務去執行。這保證了瀏覽器給與一些宏任務(如用戶輸入)以更高的優先級。好的,跟著我繼續……

宏任務(task)

瀏覽器為了能夠使得JS內部task與DOM任務能夠有序的執行,會在一個task執行結束後,在下一個 task 執行開始前,對頁面進行重新渲染 (task->渲染->task->...)

在上面的例子中:

setTimeout的作用是等待給定的時間後為它的回調產生一個新的宏任務。

這就是為什麼打印‘setTimeout’在‘end’之後,即使setTimeout代碼再‘end’前面。因為打印‘end’是第一個宏任務裡面的事情,setTimeout它的回調產生一個新的宏任務,所以會在下一個事件循環的時候執行,即使是為0秒也是在‘end’之後執行promise1,promise2,在下一個

微任務(Microtasks )

微任務是在當前宏任務 task 執行結束後立即執行的任務。

需要異步的執行任務而又不需要分配一個新的宏任務 task

這樣便可以減小一點性能的開銷。

只要執行棧中沒有其他的js代碼正在執行且每個宏任務執行完,微任務隊列會立即執行。

微任務包括了mutation observe的回調還有接下來的例子promise的回調。

知道了宏任務 (task)和微任務(Microtasks ),再來分析上面的代碼。

代碼執行的時候這個時候是第一個宏任務(task),執行 start ,setTimeout生成另外一個宏任務,也就代碼掛起來了等下個事件循環的時候執行。執行Promise的時候是一個微任務,所以是等到當前宏任務執行完在走,所以執行 end 再執行微任務promise1,promise2。這個時候第一個宏任務執行完畢,第二個宏任務開始執行setTimeout。

翻譯原文:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/?utm_source=html5weekly

這篇文章希望能幫助到各位同學。


分享到:


相關文章: