什么是微任务?
- 由于一个网页或者app中的JavaScript代码都在一个主线程中执行,
- 遇到微任务时,将微任务的回调函数放入微任务队列
- 遇到宏任务时,将宏任务的回调函数放入宏任务队列
- 当主线程所有代码执行完后,开始顺序执行微任务,微任务的回调函数在执行过程中,遇到微任务,就将微任务添加到当前微任务队列中,遇到宏任务,就将宏任务添加到宏任务的队列中。
- 当所有微任务执行完后,开始执行宏任务队列中的回调,注意,当执行宏任务回调时,遇到微任务,依然会将微任务加入到微任务队列中,此时跳回到步骤4,优先执行微任务,当微任务队列中不再有任务时,再继续执行剩余的宏任务。
微任务
- queueMicrotask(fn)
- Promise.resolve().then(fn)
- new MutationObserver(fn).observe(el)
宏任务
- setTimeout(fn, 0)
- setInterval(fn, 0)
那么我们什么时候需要使用微任务呢?
- 在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
*/