注意:

==micro task==是==macro task==**的一个步骤

每一个**==macro task==*完成之后会执行清空一下==micro task==队列,然后再执行下一个==micro task==*就对了。

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规范文档 (opens new window)以后,发现这很显然是和微任务平行的一个操作步骤
requestAnimationFrame姑且也算是宏任务吧,requestAnimationFrameMDN的定义 (opens new window)为,下次页面重绘前所执行的操作,而重绘也是作为宏任务的一个步骤来存在的,且该步骤晚于微任务的执行

# 微任务

# 浏览器 Node
process.nextTick
MutationObserver
Promise.then catch finally

# 为什么要分宏任务和微任务?

在任务队列中,其实还分为宏任务队列(Task Queue)和微任务队列(Microtask Queue),对应的里面存放的就是宏任务微任务

首先,宏任务和微任务都是异步任务。

而宏任务和微任务的区别,就是它们执行的顺序,这也是为什么要区分宏任务和微任务。

在同步任务中,任务的执行都是按照代码顺序执行的,而异步任务的执行也是需要按顺序的,队列的属性就是先进先出(FIFO,First in First Out),因此异步任务会按照进入队列的顺序依次执行。

但在一些场景下,如果只按照进入队列的顺序依次执行的话,也会出问题。比如队列先进入一个一小时的定时器,接着再进入一个请求接口函数,而如果根据进入队列的顺序执行的话,请求接口函数可能需要一个小时后才会响应数据。

因此浏览器就会将异步任务分为宏任务和微任务,然后按照事件循环的机制去执行,因此不同的任务会有不同的执行优先级,具体会在事件循环讲到。