恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

《Vue3 从入门到大神37篇》Vue3 源码详解(七):watch 与 watchEffect 源码对比——副作用是如何被追踪的?

  • 首页
  • 资讯中心
  • /
  • 《Vue3 从入门到大神37篇》Vue3 源码详解(七):watch 与 watchEffect 源码对比——副作用是如何被追踪的?

相关资讯

专业AI机构技术架构与大模型实战应用解析 2026/8/2 18:49:07
AI显微图像增强技术:原理、应用与优化 2026/8/2 18:49:08
AI系统安全治理:自主智能体行为约束与防控机制 2026/8/2 18:49:08

最新资讯

HyperMesh 3D模块体网格生成全流程:从几何清理到质量检查
DeepSeekHarness Docker版更新:从稳定运行到插件化扩展
核弹级主机实战指南:从硬件选型到CUDA深度学习环境搭建
1981-2021全球逐月太阳辐射栅格数据处理与GIS分析实战
YOLO车辆行人识别数据集从采集到部署全流程详解
Google AI Mode旅行规划升级:机票追踪、里程查询与酒店预订实战解析

今日推荐

MCU无DAC如何用定时器+DMA 2D输出高保真任意波形
Cortex-M3 Flash下载失败?从编程错误标志到供电瞬态排查
STM32 TouchGFX屏幕切换Transition优化:原理、配置与排障实战

本周热门

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析
数字电路时序基石:深入理解建立时间与保持时间
蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

本月精选

如何用DamaiHelper实现演唱会门票的智能自动化抢购:完整技术解决方案指南
第4篇:59 倍性能差距的索引瓶颈定位——一次教科书级的全表扫描调优
终极歌词批量下载神器:5分钟解决离线音乐库歌词同步难题

《Vue3 从入门到大神37篇》Vue3 源码详解(七):watch 与 watchEffect 源码对比——副作用是如何被追踪的?

发布时间:2026/8/31 16:27:55
《Vue3 从入门到大神37篇》Vue3 源码详解(七):watch 与 watchEffect 源码对比——副作用是如何被追踪的? 本篇关键词watch、watchEffect、job、scheduler、flush、pre / post / sync、cleanup难度等级⭐⭐⭐⭐⭐工程价值watch 是 Vue3 中最复杂的响应式 API。读懂它你才能真正理解“副作用调度”“异步更新”“竞态处理”这些高阶工程问题。一、开篇为什么 watch 比 computed 复杂很多同学觉得“watch 不就是监听数据变化吗”但真实情况是为什么watchEffect会自动收集依赖为什么watch需要明确指定 source为什么flush: post能拿到更新后的 DOM为什么 watch 能拿到新旧值而 watchEffect 不行为什么 watch 能防止“竞态问题”答案不在 API 层面而在调度系统Scheduler中。二、一句话区分 watch 和 watchEffectAPI本质watchEffect立即执行的副作用 自动依赖收集​watch显式数据源 惰性执行 新旧值对比 调度控制​watch 是 watchEffect 的“增强版”。三、watchEffect 源码解析自动依赖收集的真相1️⃣ 使用方式watchEffect(() { console.log(state.count) })特点✅ 立即执行✅ 自动收集依赖❌ 拿不到旧值❌ 无法精确控制触发时机2️⃣ watchEffect 的核心实现简化版源码位置packages/runtime-core/src/apiWatch.tsfunction watchEffect( effectFn, options {} ) { return doWatch(effectFn, null, options) }所有魔法都在doWatch里。3️⃣ watchEffect 的 effect 创建const effect new ReactiveEffect(effectFn) effect.scheduler () { if (flush sync) { job() } else { queueJob(job) } }关键点watchEffect内部也是一个ReactiveEffect通过scheduler接入 Vue 的异步调度系统默认是异步执行flush: pre4️⃣ 为什么 watchEffect 能自动收集依赖effect.run()执行effectFn时读取响应式数据触发track建立依赖关系和普通 effect 没有任何区别。四、watch 源码解析精确控制的艺术1️⃣ watch 的使用方式watch( () state.count, (newVal, oldVal) { console.log(newVal, oldVal) }, { flush: post, immediate: true } )特点✅ 明确指定 source✅ 拿到新旧值✅ 支持immediate✅ 支持deep✅ 支持flush控制2️⃣ watch 的核心实现简化版function watch(source, cb, options) { return doWatch(source, cb, options) }没错watch 和 watchEffect 共用同一个doWatch。区别在于有没有 callback。五、doWatchwatch 系统的真正大脑1️⃣ source 的三种形态Vue3 支持三种 watch source// 1️⃣ getter watch(() state.count, cb) // 2️⃣ ref watch(countRef, cb) // 3️⃣ reactive watch(state, cb, { deep: true })源码中统一处理let getter: () any if (isRef(source)) { getter () source.value } else if (isReactive(source)) { getter () source deep true } else if (isFunction(source)) { getter source }2️⃣ jobwatch 回调的执行单元const job () { if (cb) { const newValue effect.run() if (deep || hasChanged(newValue, oldValue)) { cb(newValue, oldValue) oldValue newValue } } else { effect.run() } }新旧值对比发生在 job 中而不是 trigger 中。3️⃣ 为什么 watch 能拿到旧值核心秘密let oldValue initialValue oldValue newValueeffect.run()得到新值与缓存的旧值对比符合条件才执行回调✅这就是 watch 能精准控制更新的原因。六、flush 机制pre / post / sync 的本质这是 watch 最难理解但工程价值最高的部分。1️⃣ flush: pre默认flush: pre执行时机组件更新前源码逻辑queuePreFlushCb(job)✅适合大多数业务逻辑2️⃣ flush: postflush: post执行时机组件更新后 → DOM 已更新源码逻辑queuePostRenderEffect(job, instance)✅适合操作 DOM、获取尺寸、Scroll 位置watch(source, cb, { flush: post }) onMounted(() { // 等价于 watch post })3️⃣ flush: syncflush: sync执行时机数据变化 → 立即执行源码逻辑job()⚠️慎用可能导致多次同步更新性能差。七、deep watch性能与精度的权衡1️⃣ 为什么 reactive 默认 deepwatch(state, cb)因为getter () source track(state, GET, ITERATE_KEY)一次性追踪整个对象。2️⃣ deep 的实现原理function traverse(value, seen new Set()) { if (!isObject(value) || seen.has(value)) return seen.add(value) for (const key in value) { traverse(value[key], seen) } return value }递归访问每一个属性强制触发 track。⚠️性能代价极高慎用 deep。八、cleanup解决竞态问题的关键1️⃣ 竞态问题示例watch(id, async (newId) { const res await fetchData(newId) data.value res })如果id快速变化请求 A 发出请求 B 发出B 先返回A 后返回 →数据错乱2️⃣ watch 的 cleanup 机制watch(id, async (newId, oldId, onCleanup) { let canceled false onCleanup(() { canceled true }) const res await fetchData(newId) if (!canceled) { data.value res } })源码本质const cleanup effect.onStop || (() {})每次重新执行前先执行上一次的 cleanup。✅这是前端“竞态控制”的标准解法。九、watchEffect vs watch源码级对比表维度watchEffectwatch依赖收集自动显式立即执行✅可选新旧值❌✅深度监听❌✅调度控制基础精细竞态处理❌✅适用场景副作用数据变化响应十、调试实战观察 watch 的调度过程在 VSCode 中打这些断点packages/runtime-core/src/apiWatch.ts ├── doWatch() ├── job() ├── queueJob() └── cleanup()测试代码watchEffect(() { console.log(effect, state.count) }) watch(() state.count, (n, o) { console.log(watch, n, o) }) state.count观察queueJob何时入队job何时执行DOM 更新前后顺序你会彻底理解 Vue3 的异步更新机制。十一、工程最佳实践✅ 优先使用 watchEffectwatchEffect(() { document.title state.title })✅ DOM 相关用 flush: postwatch(element, () { el.getBoundingClientRect() }, { flush: post })✅ 异步请求必用 cleanupwatch(id, (newId, _, onCleanup) { const abort new AbortController() onCleanup(() abort.abort()) fetch(url, { signal: abort.signal }) })❌ 避免 deep watch// ❌ 性能差 watch(state, cb, { deep: true }) // ✅ 精确监听 watch(() state.user.name, cb)十二、本篇总结✅ watch / watchEffect 共用doWatch✅ 调度系统queueJob是异步更新的核心✅ flush 控制执行时机pre / post / sync✅ cleanup 是解决竞态问题的关键✅ deep watch 有显著性能代价一句话升华watch 的本质不是“监听数据”而是“在正确的时机以正确的方式执行正确的副作用”。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号