1.什么是宏任务和微任务
JavaScript把异步任务又做了进一步的划分,异步任务又分为两类,分别是:
-
宏任务(macrotask):
- 异步Ajax请求
- setTimeout 、setInterval
- 文件操作
- 其他宏任务
-
微任务(microtask):
- Promise.then、Promise.catch和Promise.finally
- process.nextTick
- 其他微任务
2. 宏任务和微任务的执行顺序
每一个宏任务执行完之后,都会检查是否存在待执行的微任务,
如果有,则执行完所有的微任务之后,再执行下一个宏任务。
宏任务和微任务交替执行。
3. 利用情景加以理解
假设去银行办业务:
-
A 和 B 去银行办业务。首先,需要取号之后进行排队
- 宏任务队列
-
假设当前银行网点只有一个柜员,A 在办理存款业务时,B 只能等待
- js单线程,宏任务按次序执行
-
A 办完存款业务后,柜员询问他是否还想办理其他业务
- 当前宏任务执行完,检查是否有微任务
-
A 告诉柜员:想买理财产品,再办个信用卡(主业务办完后,又临时新增了一些业务去办理)
- 执行微任务,后续宏任务被推迟
-
A 离开柜台后,柜员开始为 B 办理业务
- 所有微任务执行完毕,开始执行下一个宏任务
4. 分析以下代码的输出顺序
setTimeout(function() {console.log('1');})
new Promise(function(resolve) {
console.log('2');
resolve()
}).then(function() {
console.log('3');
})
console.log('4');
正确的输出顺序是: 2 4 3 1
分析
- 先执行所有的同步任务:输出 2 4
- 再执行微任务:输出 3(在执行宏任务之前,要先检查有没有未完成的微任务)
- 再执行下一个宏任务:输出 1
5. 经典面试题
console.log('1');
setTimeout(function() {
console.log('2');
new Promise(function(resolve) {
console.log('3');
resolve()
}).then(function() {
console.log('4');
})
})
new Promise(function(resolve) {
console.log('5');
resolve()
}).then(function() {
console.log('6');
})
setTimeout(function() {
console.log('7');
new Promise(function(resolve) {
console.log('8');
resolve()
}).then(function() {
console.log('9');
})
})
正确输出顺序: 1 5 6 2 3 4 7 8 9
分析
- 第一行中,同步任务
- A块中,这个定时器的回调函数属于异步任务里面的宏任务,一整个放入宏任务队列进行等待
- B块中,五属于同步任务,六属于微任务
- C块中,和A块一样,一整个放入宏任务队列
- 所以,先执行同步任务 1 5
- 再执行微任务 6,现在只剩下宏任务队列的两个任务了
- 会先执行A块,执行 2 3 4
- 再执行 C块,执行 7 8 9