微任务和宏任务执行顺序
同步任务>微任务>宏任务
宏任务
包括整体代码script,setTimeout,setInterval、I/O、UI render。
微任务
Promise、Object.observe、MutationObserver。
第一步,先按同步代码顺序运行
第二步,开始清空微任务队列
第三步,开始清空宏任务队列(执行一个宏任务,把相关微任务添加入微任务队列)
第四步:开始清空微任务队列(上一个执行宏任务中加入队列的微任务一次性全部执行完成)
第五步:开始清空宏任务队列(执行下一个宏任务,把相关微任务添加入微任务队列)
..........循环一直到执行完成
下面是宏任务和微任务的一些分配
(这里声明下,整段js代码就是第一个大的宏任务,事件循环是由这第一个宏任务开始的,然后分出微任务,这里是为了理解微任务宏任务的执行区别就先跳过这第一层)
<script>
setTimeout(function () {//宏任务1
console.log('1');
});
new Promise(function (resolve) {
console.log('2');//同步任务1
resolve();
}).then(function () {//微任务1
console.log('3');
});
console.log('4');//同步任务2
setTimeout(function () {//宏任务2
console.log('5');//宏任务2中的同步任务
new Promise(function (resolve) {
console.log('6');//宏任务2中的同步任务
new Promise(function (resolve) {//宏任务2中的微任务
console.log('x1');
resolve();
}).then(function () {
console.log('X2');
});
setTimeout(function () {//宏任务2中的宏任务
console.log('X3');
new Promise(function (resolve) {//宏任务2中的宏任务中的同步任务
console.log('X4');
resolve();
}).then(function () {//宏任务2中的宏任务中的微任务
console.log('X5');
});
})
resolve();
}).then(function () {//宏任务2中的微任务
console.log('7');
});
})
setTimeout(function () {//宏任务3
console.log('8');
});
//(对于这段代码node环境和浏览器环境输出一致)
//输出答案:2,4,3,1,5,6,x1,x2,7,8,x3,x4,x5
</script>
任务详解
为什么有了宏任务后,还是会有微任务的存在?那是因为宏任务太占用性能,当需要一些较早就准备好的方法,排在最后才执行的时候,又不想新增一个宏任务,那么就可以把这些方法,一个一个的放在微任务队列里面,在这个宏任务中的代码执行完后,就会执行微任务队列。
因此当前同步代码执行,遇到异步任务,如果是异步宏任务,放入下一轮宏任务队列,是异步微任务,放入微任务队列跟在当前宏任务屁股后面。微任务相当于宏任务的小尾巴,因此当前宏任务执行完,在它后面等着的异步微任务就会被立刻放入队列继续执行。而异步的宏任务需要等到下一轮,从而造成了异步中微任务在宏任务之前执行的情况。