众所周知,JavaScript是基于事件循环而运行的,微任务与宏任务是事件循环中重要概念。自node火起来后,这个知识点就成了面试官压轴大题,所以我们必须要会。
JavaScript的异步最开始的时候是基于一个个的回调函数,而事件循环中任务,说白了也就是一个个的函数,毕竟函数是JavaScript中的一等公民。那么什么是微任务,什么又是宏任务呢?其实是通过执行的时机来区分的:
微任务:在本次任务执行完后执行。
宏任务:在下一个任务循环的时候执行。
这里有一张经典的图片,供大家参考:
每次事件的循环的执行都是以宏任务开始的。如果本次宏任务执行完毕了,那么就会检索是否有微任务,如果有,那么就去执行微任务,如果微任务执行完或者没有微任务的话那么就会进入下次事件循环。
常见的宏任务:setTimeout、setInterval、setImmediate(Node特有)、requestAnimationFrame(浏览器特有)。
常见的微任务:Promise中的then/catch/finally方法、process.nextTick(Node特有)。
这里需要注意一点是Promise的构造方法在new的时候会立即执行。
下面来看一个老掉牙的经典面试题吧:
1 | console.log('1'); |
分别打印:1 7 6 8 2 4 3 5 9 11 10 12
。如果和你的预期是一样的说明你已经掌握了,就没必要看下面的分解步骤了。
- 首先打印1。第3行遇到
setTimeout
加入到宏任务队列中,下次处理。第16行,遇到微任务process.nextTick
,加入到微任务的队列中。第20行new Promise
会立即执行传递的函数打印7
,将then放在微任务队列中。第20行发现setTimeout
,放入宏任务队列中。 - 本次任务执行完后,检测微任务,发现有2个,一个是第16行的
process.nextTick
,一个是23行的then
,分别执行,打印6和8。 - 执行下一个宏任务,也就是第3行的
setTimeout
,分别打印2和4,发现有2个微任务,分别打印3和5。 - 执行下一个宏任务,也就是第27行的
setTimeout
,分别打印9和11,发现有2个微任务,分别打印10和12。