参考资料:https://zh.javascript.info/microtask-queue#wei-ren-wu-dui-lie-microtaskqueue
简化版 Vue3 中的 微任务队列实例及说明:
// 任务队列
const queue = []
// 创建一个异步函数
const task = Promise.resolve()
function nextTick(fn) {
task.then(fn)
}
// k 这个参数是为了调试
function queueJob(job, k) {
// 如果队列中不存在这个 任务,则先存入队列
if(!queue.find(c => c.job === job)) {
queue.push({ job, key: k})
// 执行所有的任务
queueFlush()
}
}
function queueFlush() {
const taskFn = () => {
let job;
// 每执行完成一个任务就从队列中移除
while ((job = queue.shift())) {
if (job) {
// 输出的是第几次加入队列的函数
console.log(job.key)
job.job();
}
}
}
// taskFn 这个函数其实并没有被立即执行,而是先存入了 微任务队列(PromiseJobs)
// 需要等待当前代码执行完成并且先前排队的处理程序(handler)都完成时才会被执行
// 由于每次都会执行所有任务后都会清空队列
// 所以保证只会执行最后一次放入 queue 队列的所有任务
nextTick(taskFn)
}
// ---- 测试 ----
let i = 0
function fn1() {
console.log(i)
}
i++
// 输出 -> 11
// 该任务没有被立即执行,而是等待当前代码执行完成之后才被执行,所以 i = (0 + 1 + 10) = 11
queueJob(fn1, 'a')
i += 10
queueJob(fn1, 'b') // 不会被加入队列,因为队列中已经存在该任务了
在Vue3中,利用 微任务 队列确保不会因为依赖而导致许多不必要的更新,比如:
const count = ref(0)
<template>
<div>{{ count }}</div>
<tempalte>
for(let i = 0; i < 100; i++) {
count ++
}
如果没有通过微任务进行管理,那么会更新100次,但是只有当 for 被执行完成之后更新才是有必要的,Vue3就是利用微任务的特点来进行统一管理的