scheduler 是协调更新时机与顺序的中枢,负责去重、排序、微任务调度更新任务,不直接操作 dom;它收集响应式变化为队列,flushjobs 在微任务中执行 effect.run() 触发 render 和 patch。

Scheduler 调度器不是“执行更新”的工具,而是“决定何时、以何种顺序、合并哪些更新”的协调中枢。它不直接操作 DOM,也不生成虚拟节点,它的核心职责是:把零散的响应式变化,组织成一批高效、有序、去重的更新任务,并在浏览器空闲时机(微任务)统一执行。
它解决的是什么问题?
没有 Scheduler 时,数据一变就立刻 render + patch,会导致:
- 同一组件多次修改同一数据,触发多次重复渲染
- 父子组件更新顺序错乱(子先于父),引发状态不一致或警告
- 同步执行阻塞主线程,页面卡顿,尤其在高频输入或循环更新场景
- 无法与 nextTick、watchEffect 等 API 协同,生命周期不可控
它怎么管理异步更新队列?
关键不在“异步”本身,而在“队列控制逻辑”:
- 去重机制:同一个组件的 render effect 被多次触发,只保留最后一次进队列,避免冗余更新
- 微任务调度:使用 Promise.resolve().then() 触发 flushJobs,确保在当前同步代码结束后、下一次渲染前执行
- 排序保障:刷新队列前对 job 排序,父组件 effect 总是排在子组件之前,符合依赖顺序
- 嵌套安全:更新中产生的新 job(如 computed 重新求值触发的副作用),会被合并进当前队列或推入下一轮,防止无限递归
它和 Patch 函数什么关系?
Patch 是纯同步的“最后一公里”:
- Scheduler 负责把需要更新的组件 effect 收集、排队、排序、触发 run()
- effect.run() 内部调用 render() 生成新 VNode,再传给 patch() 做真实 DOM 差分更新
- Patch 完全不知道自己被谁调用、是否在 nextTick 里——它只认 VNode,只做同步比对和打补丁
它在 Vue 3 中长什么样?
本质是一个轻量级任务队列 + 微任务驱动器:
- 任务队列 queue: SchedulerJob[] 存储待执行的更新函数
- queueJob(job) 入队前检查是否已存在,保证唯一性
- flushJobs() 在微任务中清空队列,逐个执行 job(即组件更新逻辑)
- 整个过程不依赖宏任务(如 setTimeout),避免 4ms+ 延迟,更及时










