Vue3 的响应式系统源码级 effect 的调度器(scheduler)机制与任务队列原理
字数 1099 2025-11-21 01:26:08

Vue3 的响应式系统源码级 effect 的调度器(scheduler)机制与任务队列原理

1. 调度器的基本概念

在 Vue3 的响应式系统中,副作用函数(effect)默认在依赖变更时同步执行。但某些场景下需要控制执行时机(如批量更新、异步执行),这时需通过调度器(scheduler)实现。调度器是 effect 的配置选项,允许开发者自定义依赖触发后的执行逻辑。

2. 调度器的源码结构

packages/reactivity/src/effect.ts 中,ReactiveEffect 类的构造函数包含调度器参数:

class ReactiveEffect {
  constructor(
    public fn: Function,
    public scheduler?: Function // 可选调度器
  ) {}
}

当依赖更新触发 trigger 时,会检查 effect 是否有调度器:

// trigger 函数内部逻辑
if (effect.scheduler) {
  effect.scheduler(); // 执行调度器逻辑
} else {
  effect.run(); // 默认同步执行
}

3. 调度器的工作流程

步骤 1:依赖触发时拦截执行

假设一个 effect 配置了调度器:

const obj = reactive({ count: 0 });

effect(
  () => {
    console.log(obj.count);
  },
  {
    scheduler: (effect) => {
      // 将 effect 加入异步队列
      setTimeout(effect);
    },
  }
);

当修改 obj.count 时,不会立即执行副作用函数,而是执行 scheduler 函数,并将 effect 作为参数传入。

步骤 2:调度器的任务队列管理

Vue3 内部通过任务队列实现批量更新。例如组件更新时,多个数据变更可能触发多个 effect,但通过调度器可将这些 effect 合并到同一个任务队列中:

  1. 收集任务:在 trigger 中,将需要执行的 effect 加入 queue 队列(避免重复添加)。
  2. 异步执行:通过 Promise.resolve().then() 将队列执行推到微任务队列,实现批量更新。

步骤 3:实际应用——组件更新队列

packages/runtime-core/src/scheduler.ts 中,Vue3 维护了一个组件更新队列

const queue: ReactiveEffect[] = [];

function queueJob(job: ReactiveEffect) {
  if (!queue.includes(job)) {
    queue.push(job);
    queueFlush(); // 触发队列执行
  }
}

function queueFlush() {
  if (!isFlushing) {
    isFlushing = true;
    currentFlushPromise = Promise.resolve().then(flushJobs);
  }
}

function flushJobs() {
  // 执行队列中的所有 effect
  for (const job of queue) {
    job.run();
  }
  queue.length = 0; // 清空队列
}

组件渲染的 effect 默认配置了调度器,其 schedulerqueueJob 函数。

4. 调度器的优先级与控制

Vue3 允许通过调度器实现任务优先级控制:

  • 前置任务:某些 effect 需在组件更新前执行(如 watch 的回调)。
  • 后置任务:如 updated 生命周期钩子在组件更新后执行。
    scheduler.ts 中,队列分为 pre(前置)、normal(正常)、post(后置)三个队列,按顺序执行。

5. 总结:调度器的核心作用

  1. 控制执行时机:将同步任务转为异步,避免频繁更新。
  2. 批量更新:合并同一事件循环内的多次数据变更,减少重复渲染。
  3. 优先级调度:确保任务按正确顺序执行(如父组件优先于子组件更新)。

通过调度器机制,Vue3 实现了高效且灵活的响应式更新策略。

Vue3 的响应式系统源码级 effect 的调度器(scheduler)机制与任务队列原理 1. 调度器的基本概念 在 Vue3 的响应式系统中,副作用函数(effect)默认在依赖变更时 同步执行 。但某些场景下需要控制执行时机(如批量更新、异步执行),这时需通过 调度器(scheduler) 实现。调度器是 effect 的配置选项,允许开发者自定义依赖触发后的执行逻辑。 2. 调度器的源码结构 在 packages/reactivity/src/effect.ts 中, ReactiveEffect 类的构造函数包含调度器参数: 当依赖更新触发 trigger 时,会检查 effect 是否有调度器: 3. 调度器的工作流程 步骤 1:依赖触发时拦截执行 假设一个 effect 配置了调度器: 当修改 obj.count 时,不会立即执行副作用函数,而是执行 scheduler 函数,并将 effect 作为参数传入。 步骤 2:调度器的任务队列管理 Vue3 内部通过 任务队列 实现批量更新。例如组件更新时,多个数据变更可能触发多个 effect,但通过调度器可将这些 effect 合并到同一个任务队列中: 收集任务 :在 trigger 中,将需要执行的 effect 加入 queue 队列(避免重复添加)。 异步执行 :通过 Promise.resolve().then() 将队列执行推到微任务队列,实现批量更新。 步骤 3:实际应用——组件更新队列 在 packages/runtime-core/src/scheduler.ts 中,Vue3 维护了一个 组件更新队列 : 组件渲染的 effect 默认配置了调度器,其 scheduler 即 queueJob 函数。 4. 调度器的优先级与控制 Vue3 允许通过调度器实现 任务优先级 控制: 前置任务 :某些 effect 需在组件更新前执行(如 watch 的回调)。 后置任务 :如 updated 生命周期钩子在组件更新后执行。 在 scheduler.ts 中,队列分为 pre (前置)、 normal (正常)、 post (后置)三个队列,按顺序执行。 5. 总结:调度器的核心作用 控制执行时机 :将同步任务转为异步,避免频繁更新。 批量更新 :合并同一事件循环内的多次数据变更,减少重复渲染。 优先级调度 :确保任务按正确顺序执行(如父组件优先于子组件更新)。 通过调度器机制,Vue3 实现了高效且灵活的响应式更新策略。