JavaScript
是单线程的,JavaScript
将运行任务分为同步任务与异步任务,同步任务由JavaScript
主线程依次执行,异步任务委托给宿主环境执行,对于已完成的异步任务对应的回调函数,会被加入任务队列中等待执行。然后任务队列依次执行任务。
本文所说的宏任务和微任务说的都是上述的异步任务,它们都在任务队列中,但不同属于一个任务队列。如下图所示,列出了常见的宏任务和微任务的类型:

宏任务
宏任务(macro-task )
是指任务队列中等待主线程执行的代码块,可以理解为每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。常见的如:
- setTimeout
- setInterval
- setImmediate(Node.js 环境)
- UI rending/UI事件
- I/O
- 主线程同步script代码
- xhr
- requestAnimationFrame(仅浏览器)
- MessageChannel
常见代码如下:
setTimeout(() => {
console.log('ha ha ha');
}, 0);
// 执行结果
ha ha ha
微任务
微任务(micro-task)
是指任务队列中将当前宏任务执行完后,页面渲染之前需要执行的任务,常见的微任务代码块如:
- Promise
- MutaionObserver
- Object.observe
- process.nextTick(Node.js 环境)
示例代码如下:
new Promise((resolve)=>{
console.log('1');
resolve();
}).then(()=>{
console.log('2');
}).then(()=>{
console.log('3');
})
console.log('4');
// 执行结果
1
4
2
3
交替执行
如下通过一个示例来看下宏任务、微任务交替执行的执行结果:
//主线程直接执行
console.log('1');//主线程任务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');//微任务1
})
//主线程直接执行
new Promise(function(resolve) {
console.log('7');//主线程任务2
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