Skip to content

1.简单实现响应式

javascript
function effect() {
  document.body.innerText = obj.text;
}
const bucket = new Set();
const data = { text: "hello world" };
const obj = new Proxy(data, {
  get(target, key) {
    bucket.add(effect);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    bucket.forEach((fn) => fn());
    return true;
  },
});
effect();
setTimeout(() => {
  obj.text = "hello vue3";
}, 1000);
function effect() {
  document.body.innerText = obj.text;
}
const bucket = new Set();
const data = { text: "hello world" };
const obj = new Proxy(data, {
  get(target, key) {
    bucket.add(effect);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    bucket.forEach((fn) => fn());
    return true;
  },
});
effect();
setTimeout(() => {
  obj.text = "hello vue3";
}, 1000);

2.副作用函数的优化

javascript
function effect() {
  document.body.innerText = obj.text;
}
const bucket = new Set();
const data = { text: "hello world" };
const obj = new Proxy(data, {
  get(target, key) {
    bucket.add(effect);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    bucket.forEach((fn) => fn());
    return true;
  },
});
effect();
setTimeout(() => {
  obj.text = "hello vue3";
}, 1000);
function effect() {
  document.body.innerText = obj.text;
}
const bucket = new Set();
const data = { text: "hello world" };
const obj = new Proxy(data, {
  get(target, key) {
    bucket.add(effect);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    bucket.forEach((fn) => fn());
    return true;
  },
});
effect();
setTimeout(() => {
  obj.text = "hello vue3";
}, 1000);

3.依赖收集

javascript
const buckct = new WeakMap();
let activeEffect;
const data = { text: "hello world" };

//依赖函数
function effect(fn) {
  activeEffect = fn;
  fn();
}

// 代理对象
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
  // weakMap 由target和map构成
  // map 由key 和 set构成
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1,f2,f3] type:set
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key);
  effects && effects.forEach((fn) => fn());
}

// 第一次收集依赖
effect(() => {
  console.log("effect fn");
  document.body.innerText = obj.text;
  // 第一次读取触发代理对象的读取操作,并将effect函数建立和obj依赖
});
setTimeout(() => {
  obj.text = "hello vue3";
  // obj.name ='我是没有建立依赖的属性呀' // 由于新的属性没有建立对应的依赖,所以函数不会在此执行
}, 1000);
const buckct = new WeakMap();
let activeEffect;
const data = { text: "hello world" };

//依赖函数
function effect(fn) {
  activeEffect = fn;
  fn();
}

// 代理对象
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
  // weakMap 由target和map构成
  // map 由key 和 set构成
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1,f2,f3] type:set
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key);
  effects && effects.forEach((fn) => fn());
}

// 第一次收集依赖
effect(() => {
  console.log("effect fn");
  document.body.innerText = obj.text;
  // 第一次读取触发代理对象的读取操作,并将effect函数建立和obj依赖
});
setTimeout(() => {
  obj.text = "hello vue3";
  // obj.name ='我是没有建立依赖的属性呀' // 由于新的属性没有建立对应的依赖,所以函数不会在此执行
}, 1000);

4.引入切换分支与 cleanup

javascript
const buckct = new WeakMap();
let activeEffect;
const data = { ok: true, text: "hello world" };

//依赖函数
function effect(fn) {
  activeEffect = fn;
  fn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
  // weakMap 由target和map构成
  // map 由key 和 set构成
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1,f2,f3] type:set
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key);
  effects && effects.forEach((fn) => fn());
}

effect(() => {
  console.log("effect fn");
  document.body.innerText = obj.ok ? obj.text : "not";
});
obj.ok = false;
obj.text = "hello dadada";
// 当obj.ok 属性为false的时候,map中依然存在 ok 和 text的2个依赖,按理来说我们只需要ok的依赖,而不需要set的依赖,以为当我们执行set依赖的时候页面并不会刷新内容, 而且当我们修改obj.text值得时候,仍然会导致副作用函数重复执行,即使document.body.innertext值不需要改变
// 既 理想状态下副作用函数不应该被字段obj.text收集依赖
console.log(buckct);
// 我们在下节探讨如何消除这种依赖
const buckct = new WeakMap();
let activeEffect;
const data = { ok: true, text: "hello world" };

//依赖函数
function effect(fn) {
  activeEffect = fn;
  fn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
  // weakMap 由target和map构成
  // map 由key 和 set构成
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1,f2,f3] type:set
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key);
  effects && effects.forEach((fn) => fn());
}

effect(() => {
  console.log("effect fn");
  document.body.innerText = obj.ok ? obj.text : "not";
});
obj.ok = false;
obj.text = "hello dadada";
// 当obj.ok 属性为false的时候,map中依然存在 ok 和 text的2个依赖,按理来说我们只需要ok的依赖,而不需要set的依赖,以为当我们执行set依赖的时候页面并不会刷新内容, 而且当我们修改obj.text值得时候,仍然会导致副作用函数重复执行,即使document.body.innertext值不需要改变
// 既 理想状态下副作用函数不应该被字段obj.text收集依赖
console.log(buckct);
// 我们在下节探讨如何消除这种依赖

5.完善切换分支

javascript
const buckct = new WeakMap();
const data = { ok: true, text: "hello world" };
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;

function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    fn(); // 收集依赖``
  };
  effectFn.deps = [];
  effectFn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  // console.log(effects)
  const effectsToRun = new Set(effects);
  // console.log(...effectsToRun)
  effectsToRun.forEach((effectFn) => {
    // console.log(effectFn)
    effectFn();
  });
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    // console.log(deps) // deps => Set[f]
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}
effect(() => {
  console.log("effect fn");
  document.body.innerText = obj.ok ? obj.text : "not";
});
// 当第一次effect函数执行完毕之后(收集依赖的过程)会对obj.ok obj.text 收集依赖, 并且activeEffect.deps(数组)中包含2个set依赖(即2个属性的依赖)
obj.ok = false;
// console.log(activeEffect.deps)
obj.text = "dada";
// obj.text ='dadadadad'
const buckct = new WeakMap();
const data = { ok: true, text: "hello world" };
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;

function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    fn(); // 收集依赖``
  };
  effectFn.deps = [];
  effectFn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  // console.log(effects)
  const effectsToRun = new Set(effects);
  // console.log(...effectsToRun)
  effectsToRun.forEach((effectFn) => {
    // console.log(effectFn)
    effectFn();
  });
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    // console.log(deps) // deps => Set[f]
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}
effect(() => {
  console.log("effect fn");
  document.body.innerText = obj.ok ? obj.text : "not";
});
// 当第一次effect函数执行完毕之后(收集依赖的过程)会对obj.ok obj.text 收集依赖, 并且activeEffect.deps(数组)中包含2个set依赖(即2个属性的依赖)
obj.ok = false;
// console.log(activeEffect.deps)
obj.text = "dada";
// obj.text ='dadadadad'

6.嵌套的 effect.js

javascript
const buckct = new WeakMap();
const data = { foo: true, bar: true };
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;
let temp1, temp2;
// effect栈
const effectStack = [];
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    // 在调用副作用函数之前把当前副作用函数压入栈中
    effectStack.push(activeEffect);
    fn(); // 收集依赖``
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
  };
  effectFn.deps = [];
  effectFn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  const effectsToRun = new Set(effects);
  effectsToRun.forEach((effectFn) => {
    effectFn();
  });
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}
debugger;
effect(function effectFn1() {
  console.log("effectFn1 执行");
  effect(function effectFn2() {
    console.log("effectFn2 执行");
    temp2 = obj.bar;
  });
  // 当执行完内部嵌套的effect函数时内层副作用函数的执行会覆盖activeEffect的值并且对obj.bar产生依赖效果
  temp1 = obj.foo;
});
// 当effect函数执行完毕后activeEffect.deps数组中包含2个set依赖,此时已经收集到了map和set的依赖,并且activeEffect.deps收集的副作用用函数是effect的内层函数,所以哪怕当我们访问外层函数进行依赖的操作,收集和触发的副作用函数都会是内层副作用函数.effectFn函数执行完毕后为
obj.foo = "dasdas";
// 当这个执行完毕之后activeEffect.deps中只有对于bar的依赖
const buckct = new WeakMap();
const data = { foo: true, bar: true };
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;
let temp1, temp2;
// effect栈
const effectStack = [];
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    // 在调用副作用函数之前把当前副作用函数压入栈中
    effectStack.push(activeEffect);
    fn(); // 收集依赖``
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
  };
  effectFn.deps = [];
  effectFn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  const effectsToRun = new Set(effects);
  effectsToRun.forEach((effectFn) => {
    effectFn();
  });
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}
debugger;
effect(function effectFn1() {
  console.log("effectFn1 执行");
  effect(function effectFn2() {
    console.log("effectFn2 执行");
    temp2 = obj.bar;
  });
  // 当执行完内部嵌套的effect函数时内层副作用函数的执行会覆盖activeEffect的值并且对obj.bar产生依赖效果
  temp1 = obj.foo;
});
// 当effect函数执行完毕后activeEffect.deps数组中包含2个set依赖,此时已经收集到了map和set的依赖,并且activeEffect.deps收集的副作用用函数是effect的内层函数,所以哪怕当我们访问外层函数进行依赖的操作,收集和触发的副作用函数都会是内层副作用函数.effectFn函数执行完毕后为
obj.foo = "dasdas";
// 当这个执行完毕之后activeEffect.deps中只有对于bar的依赖

7.避免无线递归循环

javascript
const buckct = new WeakMap();
const data = { foo: 1 };
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;
let temp1, temp2;
// effect栈
const effectStack = [];
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    // 在调用副作用函数之前把当前副作用函数压入栈中
    effectStack.push(activeEffect);
    fn(); // 收集依赖``
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
  };
  effectFn.deps = [];
  effectFn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  const effectsToRun = new Set();
  effects &&
    effectsToRun.forEach((effectFn) => {
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    });
  effectsToRun.forEach((effctFn) => effctFn());
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}

effect(() => obj.foo++);
// effect(()=>{
//     obj.foo = obj.foo + 1
// })
const buckct = new WeakMap();
const data = { foo: 1 };
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;
let temp1, temp2;
// effect栈
const effectStack = [];
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    // 在调用副作用函数之前把当前副作用函数压入栈中
    effectStack.push(activeEffect);
    fn(); // 收集依赖``
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
  };
  effectFn.deps = [];
  effectFn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  const effectsToRun = new Set();
  effects &&
    effectsToRun.forEach((effectFn) => {
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    });
  effectsToRun.forEach((effctFn) => effctFn());
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}

effect(() => obj.foo++);
// effect(()=>{
//     obj.foo = obj.foo + 1
// })

8.调度执行

javascript
const buckct = new WeakMap();
const data = { foo: 1 };
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;
let temp1, temp2;
// effect栈
const effectStack = [];
function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    // 在调用副作用函数之前把当前副作用函数压入栈中
    effectStack.push(activeEffect);
    fn(); // 收集依赖``
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
  };
  // 将options挂载到 effectFn上
  effectFn.options = options;
  effectFn.deps = [];
  effectFn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  const effectsToRun = new Set();
  //如果trigger触发的函数与当前正在执行的副作用函数相同,则不触发执行
  effects &&
    effects.forEach((effectFn) => {
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    });
  effectsToRun.forEach((effctFn) => {
    if (effctFn.options.scheduler) {
      effctFn.options.scheduler(effctFn);
    } else {
      effctFn();
    }
  });
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}

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;
  });
}

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

effect(
  () => {
    console.log(obj.foo);
  },
  // options
  {
    scheduler(fn) {
      jobQueue.add(fn);
      flushJob();
    },
  }
);
obj.foo++;
obj.foo++;
// console.log('结束了')
const buckct = new WeakMap();
const data = { foo: 1 };
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;
let temp1, temp2;
// effect栈
const effectStack = [];
function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    // 在调用副作用函数之前把当前副作用函数压入栈中
    effectStack.push(activeEffect);
    fn(); // 收集依赖``
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
  };
  // 将options挂载到 effectFn上
  effectFn.options = options;
  effectFn.deps = [];
  effectFn();
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  const effectsToRun = new Set();
  //如果trigger触发的函数与当前正在执行的副作用函数相同,则不触发执行
  effects &&
    effects.forEach((effectFn) => {
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    });
  effectsToRun.forEach((effctFn) => {
    if (effctFn.options.scheduler) {
      effctFn.options.scheduler(effctFn);
    } else {
      effctFn();
    }
  });
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}

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;
  });
}

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

effect(
  () => {
    console.log(obj.foo);
  },
  // options
  {
    scheduler(fn) {
      jobQueue.add(fn);
      flushJob();
    },
  }
);
obj.foo++;
obj.foo++;
// console.log('结束了')

9.调度执行-lazy

javascript
const buckct = new WeakMap();
const data = { foo: 1, bar: 2 };
const effectStack = [];
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;

function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    // 将外层副作用函数压入栈中
    effectStack.push(effectFn);
    // 将 res 的结果
    const res = fn(); // 收集依赖``
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  effectFn.options = options;
  effectFn.deps = [];
  if (!options.lazy) {
    effectFn();
  }
  return effectFn;
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  // console.log(effects)
  const effectToRun = new Set();
  effects.forEach((effectFn) => {
    if (effectFn !== activeEffect) {
      effectToRun.add(effectFn);
    }
  });
  effectToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    // console.log(deps) // deps => Set[f]
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}

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;
  });
}

debugger;
const effectFn = effect(() => obj.foo + obj.bar, { lazy: true });
// effect函数返回值为effectFn函数
const value = effectFn();
// console.log('end')
console.log(value);
const buckct = new WeakMap();
const data = { foo: 1, bar: 2 };
const effectStack = [];
// 此时得activeEffect是一个函数,有一个数组得属性
let activeEffect;

function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    // 将外层副作用函数压入栈中
    effectStack.push(effectFn);
    // 将 res 的结果
    const res = fn(); // 收集依赖``
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  effectFn.options = options;
  effectFn.deps = [];
  if (!options.lazy) {
    effectFn();
  }
  return effectFn;
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = buckct.get(target);
  if (!depMap) {
    buckct.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect); // [f1=>[],f2=>[],f3=>[]] type:set
  activeEffect.deps.push(deps); //
}

function trigger(target, key) {
  // 判断对象有没有和自己的属性建立依赖,如果不存在则直接终止函数
  const depMap = buckct.get(target);
  if (!depMap) return; // 判断如果没有建立联系的属性则不执行渲染函数
  const effects = depMap.get(key); // [f1=>[],f2=>[],f3=>[]] type:set
  // console.log(effects)
  const effectToRun = new Set();
  effects.forEach((effectFn) => {
    if (effectFn !== activeEffect) {
      effectToRun.add(effectFn);
    }
  });
  effectToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i];
    // console.log(deps) // deps => Set[f]
    deps.delete(effectFn);
  }
  // 重置effectFn.deps数组
  effectFn.deps.length = 0;
}

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;
  });
}

debugger;
const effectFn = effect(() => obj.foo + obj.bar, { lazy: true });
// effect函数返回值为effectFn函数
const value = effectFn();
// console.log('end')
console.log(value);

10.实现计算属性

javascript
const data = { foo: 1, bar: 2 };
let activeEffect;
const effectStack = [];
const bucket = new WeakMap();

function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    effectStack.push(effectFn);
    let res = fn();
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  effectFn.options = options;
  effectFn.deps = [];
  if (!options.lazy) {
    effectFn();
  }
  return effectFn;
}
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = bucket.get(target);
  if (!depMap) {
    bucket.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect);
  activeEffect.deps.push(deps);
}

function trigger(target, key) {
  const depMap = bucket.get(target);
  if (!depMap) return;
  const effects = depMap.get(key);
  const effectToRun = new Set();
  effects.forEach((effectFn) => {
    if (activeEffect !== effectFn) {
      effectToRun.add(effectFn);
    }
  });
  effectToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      // 如果有条度器,则把副作用函数放到scheduer中执行
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

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;
}

function computed(getter) {
  let value;
  let dirty = true;
  const effectFn = effect(getter, {
    lazy: true,
    scheduler() {
      dirty = true;
      // 当计算属性依赖的响应式数据变化时,手动调用trigger函数触发响应
      trigger(obj, value);
    },
  });
  const obj = {
    get value() {
      //  只对脏值时才计算,并将得到的值放到value中
      if (dirty) {
        value = effectFn();
        dirty = false; // 下次如果依赖的数据没有发生改变那么则下次不需要再次加载
      }
      // 当读取value时,手动调用tacj函数进行追踪
      track(obj, value);
      return value;
    },
  };
  return obj;
}
// computed计算属性是我们封装的一个代码执行库,getter函数实际就是我们的副作用执行函数,我们用effectFn来包裹
debugger;
const sumRes = computed(() => obj.foo + obj.bar);
effect(() => {
  console.log(sumRes.value);
});
obj.foo++;
const data = { foo: 1, bar: 2 };
let activeEffect;
const effectStack = [];
const bucket = new WeakMap();

function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    effectStack.push(effectFn);
    let res = fn();
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  effectFn.options = options;
  effectFn.deps = [];
  if (!options.lazy) {
    effectFn();
  }
  return effectFn;
}
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = bucket.get(target);
  if (!depMap) {
    bucket.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect);
  activeEffect.deps.push(deps);
}

function trigger(target, key) {
  const depMap = bucket.get(target);
  if (!depMap) return;
  const effects = depMap.get(key);
  const effectToRun = new Set();
  effects.forEach((effectFn) => {
    if (activeEffect !== effectFn) {
      effectToRun.add(effectFn);
    }
  });
  effectToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      // 如果有条度器,则把副作用函数放到scheduer中执行
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

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;
}

function computed(getter) {
  let value;
  let dirty = true;
  const effectFn = effect(getter, {
    lazy: true,
    scheduler() {
      dirty = true;
      // 当计算属性依赖的响应式数据变化时,手动调用trigger函数触发响应
      trigger(obj, value);
    },
  });
  const obj = {
    get value() {
      //  只对脏值时才计算,并将得到的值放到value中
      if (dirty) {
        value = effectFn();
        dirty = false; // 下次如果依赖的数据没有发生改变那么则下次不需要再次加载
      }
      // 当读取value时,手动调用tacj函数进行追踪
      track(obj, value);
      return value;
    },
  };
  return obj;
}
// computed计算属性是我们封装的一个代码执行库,getter函数实际就是我们的副作用执行函数,我们用effectFn来包裹
debugger;
const sumRes = computed(() => obj.foo + obj.bar);
effect(() => {
  console.log(sumRes.value);
});
obj.foo++;

11.watch 实现

javascript
const data = { foo: 1, bar: 2 };
let activeEffect;
const effectStack = [];
const bucket = new WeakMap();

function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    effectStack.push(effectFn);
    let res = fn();
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  effectFn.options = options;
  effectFn.deps = [];
  if (!options.lazy) {
    effectFn();
  }
  return effectFn;
}
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = bucket.get(target);
  if (!depMap) {
    bucket.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect);
  activeEffect.deps.push(deps);
}

function trigger(target, key) {
  const depMap = bucket.get(target);
  if (!depMap) return;
  const effects = depMap.get(key);
  const effectToRun = new Set();
  effects &&
    effects.forEach((effectFn) => {
      if (activeEffect !== effectFn) {
        effectToRun.add(effectFn);
      }
    });
  effectToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      // 如果有条度器,则把副作用函数放到scheduer中执行
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

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;
}

// computed计算属性是我们封装的一个代码执行库,getter函数实际就是我们的副作用执行函数,我们用effectFn来包裹
function computed(getter) {
  let value;
  let dirty = true;
  const effectFn = effect(getter, {
    lazy: true,
    scheduler() {
      dirty = true;
      // 当计算属性依赖的响应式数据变化时,手动调用trigger函数触发响应
      trigger(obj, value);
    },
  });
  const obj = {
    get value() {
      //  只对脏值时才计算,并将得到的值放到value中
      if (dirty) {
        value = effectFn();
        dirty = false; // 下次如果依赖的数据没有发生改变那么则下次不需要再次加载
      }
      // 当读取value时,手动调用tacj函数进行追踪
      track(obj, value);
      return value;
    },
  };
  return obj;
}

// // watch函数接收2个参数,一个是响应式数据,一个是响应的回调函数
// function  watch(source,cb) {
//     effect(
//         //  调用traverse函数递归读取
//         ()=>traverse(source), // 触发读取操作,从而建立联系
//         {
//             scheduler() {
//                 cb()
//             }
//         }
//     )
// }
//
function traverse(value, seen = new Set()) {
  // 如果读取的数据是原始值,或者已经被读取过,那么return
  if (typeof value !== "object" || value === null || seen.has(value)) return;
  seen.add(value); // Set[1] proxy
  for (const key in value) {
    traverse(value[key], seen); // 递归调用这个对象的每一个值,因为可能对象的属性还是一个对象。
    // 这样就可以对对象内部所有的属性进行依赖
  }
  return value; // Proxy{foo: 1, bar: 2}
}
//
// watch(obj,()=>{
//     console.log('数据发生改变')
// })
// obj.foo++
// obj.bar++
function watch(source, cb) {
  let getter;
  if (typeof source === "function") {
    getter = source;
  } else {
    getter = () => traverse(source);
  }
  let oldValue, newValue;
  const effectFn = effect(
    () => getter(), // 对用户自己传入得数据进行依赖收集
    {
      lazy: true,
      scheduler() {
        // 在scheduler刷新之前执行副作用函数得到的是新值
        newValue = effectFn();
        // 将旧值和新值作为回调函数参数
        cb(newValue, oldValue);
        // 更新旧值,不然下次会得到错误的旧值
        oldValue = newValue;
      },
    }
  );
  // 手动调用副作用函数,拿到的就是旧值
  oldValue = effectFn(); // 1
}
debugger;
watch(
  () => obj.foo,
  (newValue, oldValue) => {
    console.log(`新值:${newValue}--旧值:${oldValue}`);
    // console.log('数据发生改变')
  }
);
// 当wacth函数执行完毕之后,会对我们传入得getter中得数据进行收集依赖,由于我们手动调用了oldValue = effectFn()则会拿到这个数据的返回值(旧值:1)
obj.foo++;
// 首先会触发tack函数,由于我们之前清理了activeEffect,所以不执行,然后执行trigger函数(此时obj.foo = 2),然后由于scheduler存在,所以执行scheduler函数 里面执行effectFn => 然后在里面执行fn函数 也就是getter函数()=>obj.foo(这里foo为2,所以重新进行依赖收集),effectFn函数执行完毕拿到fn的返回值为2 也就是newValue => cb(newValue,oldValue)
const data = { foo: 1, bar: 2 };
let activeEffect;
const effectStack = [];
const bucket = new WeakMap();

function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    effectStack.push(effectFn);
    let res = fn();
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  effectFn.options = options;
  effectFn.deps = [];
  if (!options.lazy) {
    effectFn();
  }
  return effectFn;
}
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = bucket.get(target);
  if (!depMap) {
    bucket.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect);
  activeEffect.deps.push(deps);
}

function trigger(target, key) {
  const depMap = bucket.get(target);
  if (!depMap) return;
  const effects = depMap.get(key);
  const effectToRun = new Set();
  effects &&
    effects.forEach((effectFn) => {
      if (activeEffect !== effectFn) {
        effectToRun.add(effectFn);
      }
    });
  effectToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      // 如果有条度器,则把副作用函数放到scheduer中执行
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

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;
}

// computed计算属性是我们封装的一个代码执行库,getter函数实际就是我们的副作用执行函数,我们用effectFn来包裹
function computed(getter) {
  let value;
  let dirty = true;
  const effectFn = effect(getter, {
    lazy: true,
    scheduler() {
      dirty = true;
      // 当计算属性依赖的响应式数据变化时,手动调用trigger函数触发响应
      trigger(obj, value);
    },
  });
  const obj = {
    get value() {
      //  只对脏值时才计算,并将得到的值放到value中
      if (dirty) {
        value = effectFn();
        dirty = false; // 下次如果依赖的数据没有发生改变那么则下次不需要再次加载
      }
      // 当读取value时,手动调用tacj函数进行追踪
      track(obj, value);
      return value;
    },
  };
  return obj;
}

// // watch函数接收2个参数,一个是响应式数据,一个是响应的回调函数
// function  watch(source,cb) {
//     effect(
//         //  调用traverse函数递归读取
//         ()=>traverse(source), // 触发读取操作,从而建立联系
//         {
//             scheduler() {
//                 cb()
//             }
//         }
//     )
// }
//
function traverse(value, seen = new Set()) {
  // 如果读取的数据是原始值,或者已经被读取过,那么return
  if (typeof value !== "object" || value === null || seen.has(value)) return;
  seen.add(value); // Set[1] proxy
  for (const key in value) {
    traverse(value[key], seen); // 递归调用这个对象的每一个值,因为可能对象的属性还是一个对象。
    // 这样就可以对对象内部所有的属性进行依赖
  }
  return value; // Proxy{foo: 1, bar: 2}
}
//
// watch(obj,()=>{
//     console.log('数据发生改变')
// })
// obj.foo++
// obj.bar++
function watch(source, cb) {
  let getter;
  if (typeof source === "function") {
    getter = source;
  } else {
    getter = () => traverse(source);
  }
  let oldValue, newValue;
  const effectFn = effect(
    () => getter(), // 对用户自己传入得数据进行依赖收集
    {
      lazy: true,
      scheduler() {
        // 在scheduler刷新之前执行副作用函数得到的是新值
        newValue = effectFn();
        // 将旧值和新值作为回调函数参数
        cb(newValue, oldValue);
        // 更新旧值,不然下次会得到错误的旧值
        oldValue = newValue;
      },
    }
  );
  // 手动调用副作用函数,拿到的就是旧值
  oldValue = effectFn(); // 1
}
debugger;
watch(
  () => obj.foo,
  (newValue, oldValue) => {
    console.log(`新值:${newValue}--旧值:${oldValue}`);
    // console.log('数据发生改变')
  }
);
// 当wacth函数执行完毕之后,会对我们传入得getter中得数据进行收集依赖,由于我们手动调用了oldValue = effectFn()则会拿到这个数据的返回值(旧值:1)
obj.foo++;
// 首先会触发tack函数,由于我们之前清理了activeEffect,所以不执行,然后执行trigger函数(此时obj.foo = 2),然后由于scheduler存在,所以执行scheduler函数 里面执行effectFn => 然后在里面执行fn函数 也就是getter函数()=>obj.foo(这里foo为2,所以重新进行依赖收集),effectFn函数执行完毕拿到fn的返回值为2 也就是newValue => cb(newValue,oldValue)

12.watch 后续补充

javascript
const data = { foo: 1, bar: 2 };
let activeEffect;
const effectStack = [];
const bucket = new WeakMap();

function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    effectStack.push(effectFn);
    let res = fn();
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  effectFn.options = options;
  effectFn.deps = [];
  if (!options.lazy) {
    effectFn();
  }
  return effectFn;
}
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = bucket.get(target);
  if (!depMap) {
    bucket.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect);
  activeEffect.deps.push(deps);
}

function trigger(target, key) {
  const depMap = bucket.get(target);
  if (!depMap) return;
  const effects = depMap.get(key);
  const effectToRun = new Set();
  effects &&
    effects.forEach((effectFn) => {
      if (activeEffect !== effectFn) {
        effectToRun.add(effectFn);
      }
    });
  effectToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      // 如果有条度器,则把副作用函数放到scheduer中执行
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

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;
}

// computed计算属性是我们封装的一个代码执行库,getter函数实际就是我们的副作用执行函数,我们用effectFn来包裹
function computed(getter) {
  let value;
  let dirty = true;
  const effectFn = effect(getter, {
    lazy: true,
    scheduler() {
      dirty = true;
      // 当计算属性依赖的响应式数据变化时,手动调用trigger函数触发响应
      trigger(obj, value);
    },
  });
  const obj = {
    get value() {
      //  只对脏值时才计算,并将得到的值放到value中
      if (dirty) {
        value = effectFn();
        dirty = false; // 下次如果依赖的数据没有发生改变那么则下次不需要再次加载
      }
      // 当读取value时,手动调用tacj函数进行追踪
      track(obj, value);
      return value;
    },
  };
  return obj;
}

// // watch函数接收2个参数,一个是响应式数据,一个是响应的回调函数
// function  watch(source,cb) {
//     effect(
//         //  调用traverse函数递归读取
//         ()=>traverse(source), // 触发读取操作,从而建立联系
//         {
//             scheduler() {
//                 cb()
//             }
//         }
//     )
// }
//
function traverse(value, seen = new Set()) {
  // 如果读取的数据是原始值,或者已经被读取过,那么return
  if (typeof value !== "object" || value === null || seen.has(value)) return;
  seen.add(value); // Set[1] proxy
  for (const key in value) {
    traverse(value[key], seen); // 递归调用这个对象的每一个值,因为可能对象的属性还是一个对象。
    // 这样就可以对对象内部所有的属性进行依赖
  }
  return value; // Proxy{foo: 1, bar: 2}
}
//
// watch(obj,()=>{
//     console.log('数据发生改变')
// })
// obj.foo++
// obj.bar++
function watch(source, cb, options = {}) {
  let getter;
  if (typeof source === "function") {
    getter = source;
  } else {
    getter = () => traverse(source);
  }
  let oldValue, newValue;
  const job = () => {
    newValue = effectFn();
    cb(newValue, oldValue);
    oldValue = newValue;
  };
  const effectFn = effect(() => getter(), {
    lazy: true,
    scheduler: job,
  });

  if (options.immediate) {
    job();
  } else {
    oldValue = effectFn();
  }
}

watch(
  () => obj.foo,
  (newValue, oldValue) => {
    console.log(`新值:${newValue}--旧值:${oldValue}`);
    // console.log('数据发生改变')
  },
  {
    immediate: true,
  }
);

obj.foo++;
const data = { foo: 1, bar: 2 };
let activeEffect;
const effectStack = [];
const bucket = new WeakMap();

function effect(fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn);
    activeEffect = effectFn;
    effectStack.push(effectFn);
    let res = fn();
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  effectFn.options = options;
  effectFn.deps = [];
  if (!options.lazy) {
    effectFn();
  }
  return effectFn;
}
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    return target[key];
  },
  set(target, key, newValue) {
    target[key] = newValue;
    trigger(target, key);
  },
});

function track(target, key) {
  if (!activeEffect) return;
  let depMap = bucket.get(target);
  if (!depMap) {
    bucket.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect);
  activeEffect.deps.push(deps);
}

function trigger(target, key) {
  const depMap = bucket.get(target);
  if (!depMap) return;
  const effects = depMap.get(key);
  const effectToRun = new Set();
  effects &&
    effects.forEach((effectFn) => {
      if (activeEffect !== effectFn) {
        effectToRun.add(effectFn);
      }
    });
  effectToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      // 如果有条度器,则把副作用函数放到scheduer中执行
      effectFn.options.scheduler(effectFn);
    } else {
      effectFn();
    }
  });
}

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;
}

// computed计算属性是我们封装的一个代码执行库,getter函数实际就是我们的副作用执行函数,我们用effectFn来包裹
function computed(getter) {
  let value;
  let dirty = true;
  const effectFn = effect(getter, {
    lazy: true,
    scheduler() {
      dirty = true;
      // 当计算属性依赖的响应式数据变化时,手动调用trigger函数触发响应
      trigger(obj, value);
    },
  });
  const obj = {
    get value() {
      //  只对脏值时才计算,并将得到的值放到value中
      if (dirty) {
        value = effectFn();
        dirty = false; // 下次如果依赖的数据没有发生改变那么则下次不需要再次加载
      }
      // 当读取value时,手动调用tacj函数进行追踪
      track(obj, value);
      return value;
    },
  };
  return obj;
}

// // watch函数接收2个参数,一个是响应式数据,一个是响应的回调函数
// function  watch(source,cb) {
//     effect(
//         //  调用traverse函数递归读取
//         ()=>traverse(source), // 触发读取操作,从而建立联系
//         {
//             scheduler() {
//                 cb()
//             }
//         }
//     )
// }
//
function traverse(value, seen = new Set()) {
  // 如果读取的数据是原始值,或者已经被读取过,那么return
  if (typeof value !== "object" || value === null || seen.has(value)) return;
  seen.add(value); // Set[1] proxy
  for (const key in value) {
    traverse(value[key], seen); // 递归调用这个对象的每一个值,因为可能对象的属性还是一个对象。
    // 这样就可以对对象内部所有的属性进行依赖
  }
  return value; // Proxy{foo: 1, bar: 2}
}
//
// watch(obj,()=>{
//     console.log('数据发生改变')
// })
// obj.foo++
// obj.bar++
function watch(source, cb, options = {}) {
  let getter;
  if (typeof source === "function") {
    getter = source;
  } else {
    getter = () => traverse(source);
  }
  let oldValue, newValue;
  const job = () => {
    newValue = effectFn();
    cb(newValue, oldValue);
    oldValue = newValue;
  };
  const effectFn = effect(() => getter(), {
    lazy: true,
    scheduler: job,
  });

  if (options.immediate) {
    job();
  } else {
    oldValue = effectFn();
  }
}

watch(
  () => obj.foo,
  (newValue, oldValue) => {
    console.log(`新值:${newValue}--旧值:${oldValue}`);
    // console.log('数据发生改变')
  },
  {
    immediate: true,
  }
);

obj.foo++;