《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 的本质不是“监听数据”而是“在正确的时机以正确的方式执行正确的副作用”。

相关新闻

专业AI机构技术架构与大模型实战应用解析

专业AI机构技术架构与大模型实战应用解析

1. 专业AI机构的技术架构解析 当我们在讨论专业人工智能机构时,核心在于理解他们如何将前沿技术转化为实际生产力。这类机构通常具备三大核心能力:技术整合能力、场景落地能力和持续迭代能力。 以我参与过的多个AI项目经验来看,一个成熟的AI…

2026/7/24 10:42:34 阅读更多 →
AI显微图像增强技术:原理、应用与优化

AI显微图像增强技术:原理、应用与优化

1. AI显微图像增强技术概述 在生物医学和材料科学研究领域,显微镜图像质量直接影响着后续分析的准确性。传统显微图像常面临低对比度、高噪声和分辨率不足等问题,这些问题在活细胞成像、低光照条件或快速动态观察时尤为突出。AI显微图像增强技术通过深度…

2026/7/24 10:42:34 阅读更多 →
深度学习输入层参数随机初始化技术解析

深度学习输入层参数随机初始化技术解析

1. 项目概述:随机生成输入层参数的意义与应用在深度学习模型构建的初始阶段,输入层参数的初始化方式往往决定了模型训练的起点质量。传统固定值初始化方法(如全零初始化)容易导致神经元对称性问题,而Xavier、He初始化等…

2026/7/24 10:41:34 阅读更多 →

最新新闻

苏州集群注册地址挂靠和园区地址有什么区别?

苏州集群注册地址挂靠和园区地址有什么区别?

一位做跨境电商的创业者曾问我:“园区地址和集群注册不是一回事吗?我花2000块买的地址,到底属于哪一种?”——这个问题,很多苏州创业者都没搞清楚。 在苏州,地址挂靠不是一个笼统的概念,集群注册…

2026/7/24 10:48:36 阅读更多 →
大模型微调与部署实战:LoRA技术解析与生产优化

大模型微调与部署实战:LoRA技术解析与生产优化

1. 大模型微调与部署的核心挑战 大模型微调与部署正成为AI工程化落地的关键瓶颈。根据2023年OReilly的调查报告显示,超过67%的企业在将大模型投入生产环境时遭遇了性能、成本和运维方面的多重挑战。我在实际项目中最常遇到的三大痛点包括: 显存墙问题 …

2026/7/24 10:48:36 阅读更多 →
思考极客与黑客精神的融合实践产物

思考极客与黑客精神的融合实践产物

思考极客与黑客精神的融合实践产物——QiLink**以前我给工程师写过一封大厂P7/P8的一封“劝退信”:与其做AI时代的耗材,不如来这里留份“家产”** 2026年了,如果你还在大厂的P序列里卷生卷死,那你可能还没意识到危机的严重性。 今…

2026/7/24 10:48:36 阅读更多 →
大模型学习路径:从零基础到工业级落地的实战指南

大模型学习路径:从零基础到工业级落地的实战指南

1. 大模型学习路径全景解析2026年的大模型技术发展已经进入深水区,从最初的文本生成到现在的多模态交互,技术栈的复杂度呈指数级增长。作为从业五年的AI工程师,我完整经历了从Transformer架构兴起到大模型工业化落地的全过程。这条学习路径不…

2026/7/24 10:48:36 阅读更多 →
《技术大败局》新能源汽车篇(更新2)

《技术大败局》新能源汽车篇(更新2)

QiLinkOS报告:行业风险导航系列《技术大败局》新能源汽车篇(2)富比案:国内高科技知识产权第一案起因:400多人集体跳槽2003年起,比亚迪从做电池切入手机代工领域,直接动了富士康的蛋糕。郭台铭后来怒斥:"我们总共被…

2026/7/24 10:48:36 阅读更多 →
C++ std::function 深度解析:类型擦除、回调机制与实战应用

C++ std::function 深度解析:类型擦除、回调机制与实战应用

1. 项目概述:为什么我们需要 std::function?在C的世界里,函数是第一等公民吗?从C语言继承而来的函数指针,虽然能指向一个函数,但用起来总感觉隔靴搔痒——类型检查弱、语法笨拙、无法直接捕获上下文状态。随…

2026/7/24 10:47:36 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:三维 X/Y/Z 三轴空间,所有散点分布在 0~10 立方体空间内;散点使用径向渐变实现立体 3D 圆球质感;支持鼠标 / 触屏拖拽画布,…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值,并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻