JS 微任务宏任务执行顺序

发布于 2025-01-17 17:16:56 字数 3620 浏览 4 评论 0

console.log('task start')

setTimeout(()=>{
  console.log('setTimeout1')
},0)

new Promise((resolve, reject)=>{
  console.log('new Promise1')
  resolve()
}).then(()=>{
  console.log('Promise.then1')
  setTimeout(()=>{
    console.log('setTimeout2')
  },0)
  new Promise((resolve, reject)=>{
    console.log('new Promise2')
    resolve()
  }).then(()=>{
    console.log('Promise.then2')
  })
})
console.log('task end')
// 'task start' 
// 'new Promise1' 
// 'task end' 
// 'Promise.then1' 
// 'new Promise2' 
// 'Promise.then2' 
// 'setTimeout1' 
// 'setTimeout2'

我的理解:在执行微队列 microtask queue 中任务的时候,如果又产生了 microtask,那么会继续添加到队列的末尾,也会在这个周期执行,直到 microtask queue 为空停止

在宏任务中添加宏任务和微任务

console.log('task start')

setTimeout(()=>{
  console.log('setTimeout1')
  setTimeout(()=>{
    console.log('setTimeout2')
  },0)
  new Promise((resolve, reject)=>{
    console.log('new Promise2')
    resolve()
  }).then(()=>{
    console.log('Promise.then2')
  })
},0)

new Promise((resolve, reject)=>{
  console.log('new Promise1')
  resolve()
}).then(()=>{
  console.log('Promise.then1')
})

console.log('task end')
// 'task start' 
// 'new Promise1' 
// 'task end' 
// 'Promise.then1' 
// 'setTimeout1' 
// 'new Promise2' 
// 'Promise.then2' 
// 'setTimeout2'

我的理解:宏任务执行的时候微任务队列已经执行完成了,里面产生的微任务宏任务只能进入下一个事件循环

async

async function asycn1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
}

async function async2() {
  console.log('async2')
}

console.log('script start')

setTimeout(() => {
  console.log('setTimeout')
}, 0)

asycn1()

new Promise((resolve) => {
  console.log('promise1')
  resolve()
}).then(() => {
  console.log('promise2')
})

console.log('script end')
// 'script start' 
// 'async1 start' 
// 'async2' 
// 'promise1' 
// 'script end' 
// 'async1 end' 
// 'promise2' 
// 'setTimeout'

$nextTick(默认走微任务)

mounted() { 
  this.message = 'aaa' // 此时已经生成 vue 内部维护的异步队列
  setTimeout(() => { console.log('222') })
  Promise.resolve().then(res => { console.log('333') }) 
  this.$nextTick(() => { // 此时只是将回调函数 push 到上面的那个异步队列
    console.log('444') 
  }) 
  Promise.resolve().then(res => { console.log('555') })
}
// 444 --> 333 --> 555 --> 222

问题

浏览器默认执行顺序 微任务 --> dom 更新 --> 宏任务,那么 vue 使用微任务 nextTick 之后我们为什么能获得更新后的 dom 呢?

export function queueWatcher (watcher: Watcher) { // set 方法后 watcher update 时候触发
  const id = watcher.id
  if (has[id] == null) {
    has[id] = true
    if (!flushing) {
      queue.push(watcher)
    } else {
      // if already flushing, splice the watcher based on its id
      // if already past its id, it will be run next immediately.
      let i = queue.length - 1
      while (i > index && queue[i].id > watcher.id) {
        i--
      }
      queue.splice(i + 1, 0, watcher)
    }
    // queue the flush
    if (!waiting) {
      waiting = true
      if (process.env.NODE_ENV !== 'production' && !config.async) {
        flushSchedulerQueue()
        return
      }
      nextTick(flushSchedulerQueue) 
      // 个函数是微任务还是宏任务,其实都无所谓,甚至同步异步都无所谓。只要我们要操作 DOM 的回调函数放在数据变更之后就可以
    }
  }
}

所以以下情况是得不到变更后的 DOM

Vue.nextTick(()=>{
  console.log(document.querySelector('h1').innerText)
})
this.msg = 'hello'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

文章
评论
26 人气
更多

推荐作者

迎风吟唱

文章 0 评论 0

qq_hXErI

文章 0 评论 0

茶底世界

文章 0 评论 0

捎一片雪花

文章 0 评论 0

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文