javascript中的非同步 macrotask 和 microtask 簡介

龍恩0707發表於2017-10-16

javascript中的非同步 macrotask 和 microtask 簡介

什麼是macrotask?什麼是microtask?
在理解什麼是macrotask?什麼是microtask之前,我們先來看看javascript中的事件迴圈機制,先看如下面一段程式碼:

console.log(1);
setTimeout(function(){
  console.log(2);
}, 0);
console.log(3);

很明顯 上面執行的結果是 1,3,2;
上面程式碼 setTimeout的延時為0,可以理解為setTimeout為非同步函式呼叫,這是因為javascript是單執行緒的,主執行緒擁有一個執行棧以及一個任務佇列
,主執行緒會依次執行程式碼,當遇到非同步函式時候,會先將該函式入棧,所有主執行緒函式執行完畢後再將非同步函式出棧,直到所有的非同步函式執行完畢即可。

Macrotasks和Microtasks

Macrotasks和Microtasks 都屬於上述的非同步任務中的一種,他們分別有如下API:
macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks: process.nextTick, Promise, MutationObserver

setTimeout的macrotask, 和 Promise的microtask 有哪些不同,先來看下程式碼如下:

console.log(1);
setTimeout(function(){
  console.log(2);
}, 0);
Promise.resolve().then(function(){
  console.log(3);
}).then(function(){
  console.log(4);
});

上面的程式碼輸出的是 1, 3, 4, 2;

如上程式碼可以看到,Promise的函式程式碼的非同步任務會優先於setTimeout的延時為0的任務先執行。
原因是任務佇列分為 macrotasks 和 microtasks, 而promise中的then方法的函式會被推入到microtasks佇列中,而setTimeout函式會被推入到macrotasks
任務佇列中,在每一次事件迴圈中,macrotask只會提取一個執行,而microtask會一直提取,直到microsoft佇列為空為止。
也就是說如果某個microtask任務被推入到執行中,那麼當主執行緒任務執行完成後,會迴圈呼叫該佇列任務中的下一個任務來執行,直到該任務佇列到最後一個任務為止。而事件迴圈每次只會入棧一個macrotask,主執行緒執行完成該任務後又會檢查microtasks佇列並完成裡面的所有任務後再執行macrotask的任務。

Microtask的應用:
為啥要用microtask? 根據 HTML Standrad, 在每個task執行完以後,UI都會重新渲染,那麼在microtask中就完成資料更新,因此當前task
結束就可以得到最新的UI了。反之:如果新建一個task來做資料更新的話,那麼渲染會執行兩次。知乎如下回答(https://www.zhihu.com/question/55364497/answer/144215284)

相關文章