console.log('1.Start');
let flag = true;
function foo(fn) {
console.log('2.Function foo is on');
if (flag) {
setTimeout(fn);
flag = false;
} else {
// queueMicrotask()創建一個微任務
// 效果和使用Promise一樣的,都是將任務加入微任務隊列
// 待宏任務結束后依次執行
queueMicrotask(fn);
// Promise.resolve().then(fn);
}
}
foo(() => {
console.log('3.setTimeout is on');
});
foo(() => {
console.log('4.Promise is on');
});
console.log('5.End');
// 完整輸出
// 1.Start
// 2.Function foo is on
// 2.Function foo is on
// 5.End
// 4.Promise is on
// 3.setTimeout is on
因為微任務自身可以入列更多的微任務,且事件循環會持續處理微任務直至隊列為空,那么就存在一種使得事件循環無盡處理微任務的真實風險。如何處理遞歸增加微任務是要謹慎而行的。
如果可能的話,大部分開發者並不應該過多的使用微任務。在基於現代瀏覽器的 JavaScript 開發中有一個高度專業化的特性,那就是允許你調度代碼跳轉到其他事情之前,而那些事情原本是處於用戶計算機中一大堆等待發生的事情集合之中的。濫用這種能力將帶來性能問題。
通過引入 queueMicrotask(),可以避免通過 promise 去創建微任務而帶來的風險。舉例來說,當使用 promise 創建微任務時,由回調拋出的異常被報告為 rejected promises 而不是標准異常。同時,創建和銷毀 promise 帶來了事件和內存方面的額外開銷,這是正確入列微任務的函數應該避免的。