vue篇之六:调度执行

61 阅读1分钟
const bucket = new WeakMap() // 存储副作用函数的桶
let activeEffect;
let effectStack = [];

const data = { ok: true, text: 'hello world', foo: 1 }

const obj = new Proxy(data, {
    get(target, key) {
        track(target, key) // 将副作用函数 activeEffect 添加到存储副作用函数的桶中
        return target[key] // 返回属性值
    },

    set(target, key, newVal) {
        target[key] = newVal // 设置属性值
        trigger(target, key) // 把副作用函数从桶里取出并执行
    }
})
// 在 get 拦截函数内调用 track 函数追踪变化
function track(target, key) {
    if (!activeEffect) return // 没有 activeEffect,直接 return
    let depsMap = bucket.get(target)
    if (!depsMap) {
        bucket.set(target, (depsMap = new Map()))
    }
    let deps = depsMap.get(key)
    if (!deps) {
        depsMap.set(key, (deps = new Set()))
    }
    deps.add(activeEffect)
    activeEffect.deps.push(deps) // 新增 // deps 就是一个与当前副作用函数存在联系的依赖集合 // 将其添加到 activeEffect.deps 数组中
}



function trigger(target, key) {
    const depsMap = bucket.get(target)
    if (!depsMap) return
    const effects = depsMap.get(key)

    const effectsToRun = new Set()
    effects && effects.forEach(effectFn => {
        if (effectFn !== activeEffect) {
            effectsToRun.add(effectFn)
        }
    })
    effectsToRun.forEach(effectFn => {
        // 如果一个副作用函数存在调度器,则调用该调度器,并将副作用函数作为参数传递
        if (effectFn.options.scheduler) { // 新增
            effectFn.options.scheduler(effectFn) // 新增
        } else {
        // 否则直接执行副作用函数(之前的默认行为)
            effectFn() // 新增
        }
    })
 }


function effect(fn, options = {}) {
    const effectFn = () => {
        cleanup(effectFn)
        
        activeEffect = effectFn
        
        effectStack.push(effectFn)
        fn()
        effectStack.pop()
        activeEffect = effectStack[effectStack.length - 1]
    }
    
    effectFn.options = options // 新增 // 将 options 挂载到 effectFn 上
    
    effectFn.deps = []
    
    effectFn()
 }


function cleanup(effectFn) {
    for (let i = 0; i < effectFn.deps.length; i++) { // 遍历 effectFn.deps 数组
        const deps = effectFn.deps[i] // deps 是依赖集合
        deps.delete(effectFn) // 将 effectFn 从依赖集合中移除
    }
    effectFn.deps.length = 0 // 最后需要重置 effectFn.deps 数组
}


 const jobQueue = new Set()
 const p = Promise.resolve()

 // 一个标志代表是否正在刷新队列
 let isFlushing = false
function flushJob() {
    if (isFlushing) return // 如果队列正在刷新,则什么都不做

    isFlushing = true // 设置为 true,代表正在刷新
    
    p.then(() => { // 在微任务队列中刷新 jobQueue 队列
        jobQueue.forEach(job => job())
    }).finally(() => {
        // 结束后重置 isFlushing
        isFlushing = false
    })
}

//  effect(() => {
//     console.log(obj.foo)
//  }, {
//     scheduler(fn) {
//         setTimeout(fn)
//     }
//  })

//  obj.foo++

//  console.log('结束了')

effect(() => {
    console.log(obj.foo)
}, {
    scheduler(fn) {
        jobQueue.add(fn) // 每次调度时,将副作用函数添加到 jobQueue 队列中
        flushJob() // 调用 flushJob 刷新队列
    }
})

 obj.foo++
 obj.foo++