vue3 调度执行-控制执行次数

vue3 调度执行-控制执行次数

为什么要控制它的执行次数?请思考以下例子

const data = {foo: 1}
const obj = new Proxy(data, {/*...*/})
// 副作用函数
effect(() => {}
	console.log(obj.foo)
})
obj.foo++
obj.foo++

没控制前输出如下

1
2
3
// 期望
1
3

是的我们只关心结果并不关心过程 所以2这个输出是多余的。那么我们有了需求就去实现一下,注意我只是大概实现这个思路并不是讲源码,希望这样能让你更好的去理解源码

// 创建一个任务队列
const jobQueue = new Set()
// 创建一个异步函数
const p = Promise.resolve()
// 一个标志代表当前是否正在刷新队列
let isFlushing = false

function queueJob(job) {
    // 存入队列
    jobQueue.add(job)
    // 执行所有的任务
    queueFlush()
}
 
function queueFlush() {
	// 如果当前已有执行的任务就直接return
	// 应为我们只需要把副作用函数放入Set队列里即可,并不需要多次执行
    if(isFlushing) return
    // 改为执行中的状态
    isFlushing = true
    p.then(() => {
        jobQueue.forEach(item => {
            item()
        })
        // 重置isFlushing 状态
    }).finally(() => isFlushing = false)
}
 
// ---- 测试 ----
let i = 0
// effect副作用函数
const effect = function() {
    console.log(i)
}
// 改变数据后手动模拟触发了set即调用queueJob函数
i++
// 该任务没有被立即执行而是放入微任务队列,等待当前代码执行完成之后才执行务队列
// 所以 i = (0 + 1 + 10) = 11
queueJob(effect)
// 再次改变 调用queueJob函数
i += 10
// 这时不会被加入队列,因为队列中已经存在该任务了
queueJob(effect) 
// 输出
11

整段代码的意思是连续执行两次queueJob,这意味着同一个effect会被add两次但是由于Set数据结构能去重得能力,最终jobQueue 只会有一个effect副作用函数。这时queueFlush也会类似的执行两次,但是由于isFlushing 标志的存在,实际上在一个事件循环内只会执行一次,即在微任务队列里只执行一次。当微任务队列执行时会触发存在里面的副作用函数。这时i已经是11了,所以最终输出了11,并不会输出其他多余内容,符合我们的预期。

你可能感兴趣的:(vue,js,javascript,前端,vue.js)