SOURCE

const bucket = new WeakMap();
let activeEffect = null;
function track(target, key){
    if(!activeEffect) return;
    let depsMap = bucket.get(target);
    if(!depsMap){
        bucket.set(target, depsMap=new Map())
    }
    let depsEffect = depsMap.get(key);
    if(!depsEffect){
        depsMap.set(key, depsEffect=new Set())
    }
    depsEffect.add(activeEffect);
    activeEffect.deps.push(depsEffect);
}
function trigger(target, key){
    const depsMap = bucket.get(target)
    if(!depsMap) return;
    const depsEffect = depsMap.get(key);
    if(!depsEffect) return;
    let effectsToRun = new Set();
    depsEffect.forEach(effect=>{
        if(effect!==activeEffect){
            effectsToRun.add(effect)
        }
    })
    effectsToRun.forEach(effect=>{
        if(effect.option.scheduler){
            effect.option.scheduler(effect)
        }else{
            effect();
        }
    })
}
function reactive(data){
    const obj = new Proxy(data,{
        get(target, key){
            track(target, key);
            return target[key]
        },
        set(target, key, value){
            target[key] = value;
            trigger(target, key);
            return true;
        }
    })
    return obj
}

function cleanup(effectFn){
    for(let i=0;i<effectFn.deps.length;i++){
        const deps = effectFn.deps[i]; //是一个set类型的数据
        deps.delete(effectFn);
    }
    effectFn.deps.length = 0;
}

const effectStack = [];

function registerEffect (fn, option={}) {
    function effectFn(){
        activeEffect=effectFn;
        effectStack.push(activeEffect);
        cleanup(effectFn);
        const res = fn()
        effectStack.pop();
        activeEffect = effectStack[effectStack.length-1];
        return res
    }
    effectFn.deps = [];
    effectFn.option = option;
    if(!option.lazy){
        effectFn();
    }
    return effectFn;
}

const data = {
    name: '李翔',
    age: 18,
    ok: true

}

const obj = reactive(data);

const jobQueue = new Set();
const p = Promise.resolve();
let isFlushing = false;
function flushJob() {
    if(isFlushing) return;
    isFlushing = true;
    p.then(()=>{
        jobQueue.forEach(job=>job())
    }).finally(()=>{
        isFlushing = false;
    })
}

// registerEffect(()=>{
//     console.log('执行effect1')
//     registerEffect(()=>{
//         console.log('执行effect2')
//         obj.age
//     })
//     obj.name
// }, {
//     scheduler(fn){
//         setTimeout(()=>{
//             fn()
//         }, 1000)
//     }
// })
// obj.name = "dora"
// obj.age = 20

// registerEffect(()=>{
//     console.log(obj.age)
// }, {
//     scheduler(fn){
//         jobQueue.add(fn);
//         flushJob();
//     }
// })

// obj.age++
// obj.age++
// obj.age++
// obj.age++

function computed(getter){
    let dirty = true;
    let value;
    const effectFn = registerEffect(getter, {
        lazy: true,
        scheduler(){
            trigger(obj, 'value')
            dirty = true;
        }
    })
    const obj = {
        get value(){
           if(dirty){
               value = effectFn();
               dirty = false;
           }
           track(obj, 'value')
           return value;
        },
    }
    return obj;
}

const computedData = computed(()=>obj.age+10)

console.log(computedData.value)
obj.age++
console.log(computedData.value)
console 命令行工具 X clear

                    
>
console