Skip to content

Macrotask 和 Microtask

1. 概述

Macrotask 和 Microtask 表示异步任务的两种分类。

1.1 Macrotask(宏任务)

API浏览器支持Node 支持
setTimeout支持支持
setInterval支持支持
setImmediate不支持支持
requestAnimationFrame支持不支持

1.2 Microtask(微任务)

API浏览器支持Node 支持
process.nextTick不支持支持
MutationObserver支持不支持
Promise.then/catch/finally支持支持

2. 如何理解宏任务和微任务?

简单的理解就是浏览器V8引擎执行代码时首先执行主线程任务,遇到微任务扔进微任务队列,遇到宏任务扔进宏任务队列,主线程队列清空之后就去执行微任务队列,最后执行宏任务队列

几个例子
js
async function async1(){
    console.log('1')
    await async2()
    console.log('2')
}
async function async2(){
    console.log('3')
}
console.log('4')
setTimeout(function(){
    console.log('5') 
},0)  
async1();
new Promise(function(resolve){
    console.log('6')
    resolve();
}).then(function(){
    console.log('7')
})
console.log('8')

// >> 4,1,3,6,8,2,7,5

js
//主线程直接执行
console.log('1');
//丢到宏事件队列中
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
//微事件1
process.nextTick(function() {
    console.log('6');
})
//主线程直接执行
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    //微事件2
    console.log('8')
})
//丢到宏事件队列中
setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})


// >> 1,7,6,8,2,4,3,5,9,11,10,12

3. 浏览器端插入微任务的几种方法和兼容性

3.1 使用es6语法 promise

js
 Promise.resolve().then(callback)

3.2 使用MutationObserver (兼容性最好

js
function microtask(callback){
  let count = 0;
	// 通过装饰者模式,将回调函数包装一下,将执行之后的返回值保存起来
	const observe = new MutationObserver(callback);
// 为了节约开销,创建一个文本比创建一个dom可划算的多
	const textNode = document.createTextNode(String(count));
	observe.observe(textNode, {
  	// 当文本改变时触发回调
  	characterData: true
});
	// 改变文本,回调callback触发
	textNode.data = String(++count);
}

3.3 微任务API queueMicrotask(性能开销最小,nodejs支持)

js
queueMicrotask(callback)

使用MessageChannel

js
function microtask(callback) {
  const channel = new MessageChannel();
  channel.port1.onmessage = callback;
  channel.port2.postMessage('');
}