宏任务和微任务

JS 本质是单线程的,通过回调函数来实现异步操作。也就是说,在 JS 中,立即执行的代码叫做同步任务;过了一段时间之后,满足了一定条件时才执行的代码叫做异步任务。

按照这种分类,JS 的执行机制是这样的:

  1. 首先判断 JS 是同步还是异步,同步就进入主进程,异步就进入 event table
  2. 异步任务在 event table 中注册函数,当满足触发条件后,被推入 event queue
  3. 当主进程中的任务执行完时,将 event queue 的任务推入主进程

在这里插入图片描述

好的,我们现在来看一个例子:

setTimeout(() => console.log(1))

new Promise(function (resolve) {
	console.log(2)
	resolve()
}).then(() => {
	console.log(3)
})

console.log(4)

如果我们按照上面的执行机制来看这串代码,应该是这样的:

  1. setTimeout 是异步任务,进入 event table ,注册回调函数并将其推入 event queue
  2. new 是同步任务,执行 new Promise() ,打印 ‘2’
  3. Promise().then() 是异步任务,进入 event table ,注册回调函数并将其推入 event queue
  4. 执行 console.log() ,打印 ‘4’
  5. 主线程执行完毕,将 setTimeout 的回调函数推入主线程并执行,打印 ‘1’
  6. Promise().then() 的回调推入主线程,打印 ‘3’

这样看下来打印的结果应该是:‘2’ , ‘4’ , ‘1’ , ‘3’

但是,实际上的结果却是 ‘2’ , ‘4’ , ‘3’ , ‘1’ ,原因是 setTimeoutPromise().then() 不是一个 event queue 。原来,JS 单纯的按照同步任务和异步任务区分是不准确的,准确的分类是 宏任务微任务

  1. 宏任务:同步代码、setTimeoutsetInterval
  2. 微任务:Promise

按照这种分类,JS 的执行机制是:

  1. 首先在主线程中执行宏任务,当遇到宏任务的异步代码,会将其回调函数放到宏任务队列中,当遇到微任务时,会将其回调函数放到微任务队列中。
  2. 当主线程中的任务执行完毕后,先将微任务队列中的任务推入主线程中执行
  3. 直到当微任务队列中没有任务时,才将宏任务队列中的任务推入主线程中进行下一循环

以上,就是 Event Loop

在这里插入图片描述

现在,在让我们来开上边那串代码,应该是这样的:

  1. setTimeout 是异步的宏任务,将其回调函数推入宏任务队列
  2. new 是同步任务,在主线程执行,打印 ‘2’
  3. Promise().then() 是微任务,将其回调函数推入微任务队列
  4. 执行 console.log() ,打印 ‘4’
  5. 主线程执行完毕,将微任务队列中的任务推入主线程并执行,即 Promise().then() 打印 ‘3’
  6. 微任务队列空了,进入下一循环
  7. 将宏任务队列中的任务推入主线程并执行,打印 ‘1’

这样,我们得到了正确结果: ‘2’ , ‘4’ , ‘3’ , ‘1’

了解了本质之后,就可以来看些进阶的例子了:

setTimeout(() => {
  console.log(1)

  new Promise(resolve => {
    console.log(2)
    resolve()
  }).then(() => {
    console.log(3)
  })
})

new Promise(resolve => {
  console.log(4)
  resolve()
}).then(() => {
  setTimeout(() => console.log(5))

  new Promise(resolve => {
    console.log(6)
    resolve()
  }).then(() => {
    console.log(7)
  })

  console.log(8)
})

console.log(9)

还是按照上面的执行机制,来看下结果:

第一次循环:

  1. setTimeout 是异步的宏任务,将其回调函数推入宏任务队列
  2. new 是同步任务,打印 ‘4’
  3. Promise().then() 是微任务,将其回调函数推入微任务队列
  4. 执行 console.log() ,打印 ‘9’
  5. 将微任务队列中的任务推入主线程并执行
  6. setTimeout 是异步的宏任务,将其回调函数推入宏任务队列
  7. new 是同步任务,打印 ‘6’
  8. Promise().then() 是微任务,将其回调函数推入微任务队列
  9. 执行 console.log() ,打印 ‘8’
  10. 微任务队列不为空,将微任务队列中的下一个任务推入主线程并执行,打印 ‘7’,微任务队列为空

第二次循环:

  1. 将宏任务队列中的任务推入主线程,打印 ‘1’
  2. new 是同步任务,打印 ‘2’
  3. Promise().then() 是微任务,将其回调函数推入微任务队列
  4. 微任务队列不为空,将微任务队列中的任务推入主线程并执行,打印 ‘3’,微任务队列为空

第三次循环:

  1. 将宏任务队列中的下一任务推入主线程,打印 ‘5’

最终结果为:‘4’, ‘9’, ‘6’, ‘8’, ‘7’, ‘1’, ‘2’, ‘3’, ‘5’

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值