vue watch实现原理
Vue 中 watch 的实现原理
Vue 的 watch 功能基于响应式系统的依赖收集和触发机制实现。其核心原理可分为以下几个部分:
依赖收集与响应式系统
Vue 通过 Object.defineProperty 或 Proxy(Vue 3)拦截数据的读取和修改操作。当在 watch 中监听一个属性时,会触发该属性的 getter,从而将当前 watcher 添加到依赖列表中。
// 简化版依赖收集逻辑
function defineReactive(obj, key, val) {
const dep = new Dep() // 依赖管理器
Object.defineProperty(obj, key, {
get() {
if (Dep.target) { // 当前正在计算的watcher
dep.addSub(Dep.target)
}
return val
},
set(newVal) {
val = newVal
dep.notify() // 通知所有依赖的watcher更新
}
})
}
Watcher 类的作用
watch 的每个监听项会创建一个 Watcher 实例。当监听的值变化时,Watcher 会执行回调函数或重新计算表达式。
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm
this.getter = parsePath(expOrFn) // 解析属性路径(如"a.b.c")
this.cb = cb
this.value = this.get()
}
get() {
Dep.target = this // 设置当前watcher
const value = this.getter.call(this.vm, this.vm) // 触发getter收集依赖
Dep.target = null
return value
}
update() {
const oldValue = this.value
this.value = this.get()
this.cb.call(this.vm, this.value, oldValue) // 执行回调
}
}
异步更新队列
Vue 通过异步队列(nextTick)优化多次数据变更的触发效率。当监听的属性变化时,watcher 不会立即执行回调,而是被推入队列,在下一个事件循环中统一执行。
// 简化版更新队列
const queue = []
let waiting = false
function queueWatcher(watcher) {
if (!waiting) {
waiting = true
nextTick(flushQueue)
}
queue.push(watcher)
}
function flushQueue() {
queue.forEach(watcher => watcher.run())
queue.length = 0
waiting = false
}
深度监听实现
当设置 deep: true 时,Watcher 会递归遍历对象的所有属性,强制触发它们的 getter 以收集深层依赖:

function traverse(val) {
if (typeof val !== 'object') return
for (const key in val) {
traverse(val[key]) // 递归访问子属性
}
}
与计算属性的区别
watch允许执行异步操作,适合数据变化时需要执行副作用(如请求API)的场景。- 计算属性基于缓存机制,只有依赖变化时才重新计算,适合同步派生数据的场景。
性能优化建议
- 避免监听复杂嵌套对象,必要时使用
deep配合特定路径监听。 - 对于频繁变化的场景,可使用
immediate: true立即获取初始值。 - 在组件销毁前通过
unwatch()手动移除不必要的监听。






