Appearance
注意:
==micro task==是==macro task==**的一个步骤
每一个**==macro task==*完成之后会执行清空一下==micro task==队列,然后再执行下一个==micro task==*就对了。
javascript
setTimeout((_) => console.log(4));
new Promise((resolve) => {
resolve();
console.log(1);
}).then((_) => {
console.log(3);
});
console.log(2);setTimeout就是作为宏任务来存在的,而Promise.then则是具有代表性的微任务,上述代码的执行顺序就是按照序号来输出的。
所有会进入的异步都是指的事件回调中的那部分代码
也就是说new Promise在实例化的过程中所执行的代码都是同步进行的,而then中注册的回调才是异步执行的。
在同步代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在宏任务之前执行。
所以就得到了上述的输出结论1、2、3、4。
宏任务
| # | 浏览器 | Node |
|---|---|---|
I/O | ✅ | ✅ |
setTimeout | ✅ | ✅ |
setInterval | ✅ | ✅ |
setImmediate | ❌ | ✅ |
requestAnimationFrame | ✅ | ❌ |
有些地方会列出来UI Rendering,说这个也是宏任务,可是在读了HTML 规范文档以后,发现这很显然是和微任务平行的一个操作步骤requestAnimationFrame姑且也算是宏任务吧,requestAnimationFrame在MDN 的定义为,下次页面重绘前所执行的操作,而重绘也是作为宏任务的一个步骤来存在的,且该步骤晚于微任务的执行
微任务
| # | 浏览器 | Node |
|---|---|---|
process.nextTick | ❌ | ✅ |
MutationObserver | ✅ | ❌ |
Promise.then catch finally | ✅ | ✅ |
为什么要分宏任务和微任务?
在任务队列中,其实还分为宏任务队列(Task Queue)和微任务队列(Microtask Queue),对应的里面存放的就是宏任务和微任务。
首先,宏任务和微任务都是异步任务。
而宏任务和微任务的区别,就是它们执行的顺序,这也是为什么要区分宏任务和微任务。
在同步任务中,任务的执行都是按照代码顺序执行的,而异步任务的执行也是需要按顺序的,队列的属性就是先进先出(FIFO,First in First Out),因此异步任务会按照进入队列的顺序依次执行。
但在一些场景下,如果只按照进入队列的顺序依次执行的话,也会出问题。比如队列先进入一个一小时的定时器,接着再进入一个请求接口函数,而如果根据进入队列的顺序执行的话,请求接口函数可能需要一个小时后才会响应数据。
因此浏览器就会将异步任务分为宏任务和微任务,然后按照事件循环的机制去执行,因此不同的任务会有不同的执行优先级,具体会在事件循环讲到。