Skip to content

什么是微任务?

  1. 由于一个网页或者app中的JavaScript代码都在一个主线程中执行,
  2. 遇到微任务时,将微任务的回调函数放入微任务队列
  3. 遇到宏任务时,将宏任务的回调函数放入宏任务队列
  4. 当主线程所有代码执行完后,开始顺序执行微任务,微任务的回调函数在执行过程中,遇到微任务,就将微任务添加到当前微任务队列中,遇到宏任务,就将宏任务添加到宏任务的队列中。
  5. 当所有微任务执行完后,开始执行宏任务队列中的回调,注意,当执行宏任务回调时,遇到微任务,依然会将微任务加入到微任务队列中,此时跳回到步骤4,优先执行微任务,当微任务队列中不再有任务时,再继续执行剩余的宏任务。

微任务

  • queueMicrotask(fn)
  • Promise.resolve().then(fn)
  • new MutationObserver(fn).observe(el)

宏任务

  • setTimeout(fn, 0)
  • setInterval(fn, 0)

那么我们什么时候需要使用微任务呢?

  1. 在vue中,响应式对象属性的改变会触发多次,这些触发都是在主线程中顺序执行的,但是我们更新dom的操作在所有属性触发完毕之后,因此需要使用到微任务来收集响应的依赖,然后等到所有响应结束后再更新DOM,这样性能会好很多。

测试代码,检验代码的执行顺序

js
console.log('start')
this.c = 1
let data = {
    s: 'a'
}
let s = data.s

Object.defineProperty(data, 's', {
    get: function(){
        return s
    },
    set: function(val){
        console.log('set')
        Promise.resolve().then(()=>{
        this.c = 3
        console.log('obj-then')
    })
        setTimeout(()=>{
            setTimeout(()=>{
                console.log('obj-123')
            }, 0)

            console.log('obj-123')
        }, 0)
        s = val
    }
})

setTimeout(()=>{
    console.log('123')
    queueMicrotask(()=>{console.log('time-queueMicrotask')})
}, 0)

queueMicrotask(()=>{
    console.log(c)
    console.log('queueMicrotask')
})

function testThis(){
    let c = 99
    console.log('test-this')
    queueMicrotask(()=>{
        console.log('test-this: ',c)
    })
}

Promise.resolve().then(()=>{
    let res = 2
   
    console.log('promise-then')
    Promise.resolve().then(()=>{
        this.c = 3
        console.log('inner-then')
    })
    setTimeout(()=>{
         this.c = 2
        res++
        console.log('then-setTimeout')
    })
    return res
}).then(res=>{

    console.log('pr-then-then', res)
})

data.s = 'b'
testThis()

console.log('end')

/** 打印顺序
  start
  set
  test-this
  end
  1
  queueMicrotask
  promise-then
  obj-then
  test-this:  99
  inner-then
  pr-then-then 2
  123
  time-queueMicrotask
  obj-123
  then-setTimeout
  obj-123
 */