【JS】Promise与setTimeout执行顺序

 Promise和setTimeout都是处理异步操作的重要工具,那么它们实际的执行顺序是怎么样的呢?

先来看下面的案例:

console.log(1)

setTimeout(()=>{
  console.log(2)
})

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

console.log(5)

// 打印结果为13542

执行原因

事件循环与任务队列

以上案例结果打印的原因,前提需要了解一下JavaScript的事件循环和任务队列,JavaScript引擎中有一个事件循环,它会不断地从任务队列中取出任务并执行。这些任务可以是同步任务,也可以是异步任务。同步任务会立即执行,而异步任务则会在满足一定条件后(如请求返回结果、定时器时间到达等)被添加到任务队列中等待执行。

js代码在执行的时候,会先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后,再将异步宏任务从队列中调入主线程执行,一直循环至所有的任务执行完毕(完成一次事件循环EventLoop)。

宏任务与微任务

现在我们来分析Promise和setTimeout的执行顺序。当我们在代码中同时使用Promise和setTimeout时,由于Promise是微任务(microtask),而setTimeout是宏任务(macrotask),根据JavaScript的事件循环机制,微任务会优先于宏任务执行。因此,Promise里的代码通常会比setTimeout先执行。

常见宏任务,包括以下几种:

  • 主代码块:JavaScript中的主线程代码;
  • 定时器任务:setTimeout和setInterval;
  • I/O操作:例如文件读写、网络请求;
  • UI渲染:浏览器需要重排或者重绘的任务;
  • 用户交互事件:例如点击、滚动、输入等用户操作触发的事件。

常见微任务,包括以下几种:

  • Promise回调函数:promise的处理程序(then、catch、finally);
  • MutationObserver:监听DOM变化的任务;
  • process.nextTick(node.js环境下):当前“执行栈”结束后立即执行的任务;

这里需要注意的是new Promise实例对象中的代码时同步执行的,会立即执行。

再来看下面的例子:

console.log(1)

setTimeout(() => {
  console.log(2)
})

new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log(7)
  })
  resolve()
  // reject()
  console.log(3)

  new Promise((resolve) => {
    setTimeout(() => {
      console.log('a')
    })
    resolve()
    console.log('b')
  })
    .then(() => {
      setTimeout(() => {
        console.log('c')
      })
      console.log('d')
    })
    .catch(() => {
      console.log('e')
    })
})
  .then(() => {
    setTimeout(() => {
      console.log(6)
    })
    console.log(4)
  })
  .catch(() => {
    console.log(8)
  })

console.log(5)

// 打印结果为13b5d427ac6
console.log(1)

setTimeout(() => {
  console.log(2)
})

new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log(7)
  })
  // resolve()
  reject()
  console.log(3)

  new Promise((resolve) => {
    setTimeout(() => {
      console.log('a')
    })
    resolve()
    console.log('b')
  })
    .then(() => {
      setTimeout(() => {
        console.log('c')
      })
      console.log('d')
    })
    .catch(() => {
      console.log('e')
    })
})
  .then(() => {
    setTimeout(() => {
      console.log(6)
    })
    console.log(4)
  })
  .catch(() => {
    console.log(8)
  })

console.log(5)


// 打印结果为 13b5d827ac
执行顺序,如下:
从上到下依次执行,遇到setTimeout,就放到宏任务队列中,遇到promise,实例对象中的代码遇到会立刻执行,如果其中也有setTimeout,也放到宏任务队列中,遇到.then、.catch,放到异步队列中,同步执行完后,开始执行微任务队列中的任务,执行完微任务,再执行宏任务队列中的任务。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值