5调度执行


// 用一个全局变量存储被注册的副作用函数
let activeEffect;
// effect 栈(避免嵌套副作用函数发生错乱)
const effectStack = [];

// 存储副作用函数的桶
const bucket = new WeakMap();
const data = {
  foo: 1
};

//定义一个任务队列
const jobQueue = new Set()
// 使用 Promise.resolve()创建一个 promise 实例,我们用它将一个任务添加到微任务队列 
const p = Promise.resolve()//一个标志代表是否正在刷新队列
let isFlushing = false

function flushJob() { // 如果队列正在刷新, 则什么都不做
  if (isFlushing) return // 设置为 true, 代表正在刷新
  isFlushing = true
  // 在微任务队列中刷新 jobQueue 队列
  p.then(() => {
    jobQueue.forEach(job => job())
  }).finally(() => { //结束后重置 isFlushing 
    isFlushing = false
  })

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

const obj = new Proxy(data, {
  //拦截读取操作
  get(target, key) {
    //将副作用函数 activeEffect 添加到存储副作用函数的桶中
    track(target, key);
    // 返回属性值
    return target[key];
  },
  //拦截设置操作
  set(target, key, newVal) {
    //设置属性值
    target[key] = newVal;
    // 把副作用函数从桶里取出并执行
    trigger(target, key);
  },
});
obj.foo++
obj.foo++
effect(() => {
  console.log(obj.foo)
});


//在get 拦截函数内调用 track 函数追踪变化
function track(target, key) {
  // 没有 activeEffect,直接 return
  if (!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中
  deps.add(activeEffect);
  // 将其添加到activeEffect.deps数组中
  activeEffect.deps.push(deps);
}
//在set 拦截函数内调用 trigger 函数触发变化
function trigger(target, key) {
  const depsMap = bucket.get(target);
  if (!depsMap) return;
  const effects = depsMap.get(key);
  const effectsToRun = new Set();
  effects && effects.forEach(effect => {
    // 如果trigger触发执行的副作用函数与当前正在执行的副作用函数相同,则不触发执行(避免无限递归)
    if (effect !== activeEffect) {
      effectsToRun.add(effect);
    }
  });
  effectsToRun && effectsToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      effectFn.options.scheduler(effectFn); //新增
    } else {
      effectFn()
    }
  });
}

function effect(fn, options = {}) {
  const effectFn = () => {
    // debugger
    //  调用cleanup 函数清除依赖
    cleanup(effectFn);
    // 当 effectFn 执行时,将其设置为当前激活的副作用函数
    activeEffect = effectFn;
    // 在调用副作用函数之前,将当前副作用函数压入 effectStack 栈中
    effectStack.push(effectFn);
    fn();
    // 当 effectFn 执行完毕,将其从 effectStack 中移除
    effectStack.pop();
    activeEffect = effectStack[effectStack.length - 1];
  };
  // 将options挂载到effectFn上
  effectFn.options = options;
  // activeEffect.deps 用来存储所有与该副作用函数相关联的依赖集合 effectFn.deps[]
  effectFn.deps = [];

  //执行副作用函数
  effectFn();
}

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

Last updated