Vue 作为一款流行的前端框架,其响应式系统一直是核心竞争力之一。本文将带你深入 Vue 3 的源码,系统地剖析其响应式原理,包括
Proxy的使用、依赖收集、更新机制等,揭开“魔法”背后的原理。
前言
Vue 的响应式系统让我们能够轻松构建交互式界面,它背后的核心理念是:当数据变化时,视图会自动更新。从 Vue 2 的 Object.defineProperty 到 Vue 3 的 Proxy,响应式系统经历了巨大升级。
本文将从以下几个方面进行分析:
-
响应式系统整体设计
-
reactive的实现原理 -
依赖收集与更新机制
-
effect的作用与运行流程 -
总结与优化建议
响应式系统整体设计
Vue 3 的响应式系统主要基于以下几个模块:
| 模块名 | 作用描述 |
|---|---|
reactive | 创建响应式对象 |
effect | 注册副作用函数,触发依赖收集 |
track | 在 getter 中收集依赖 |
trigger | 在 setter 中触发更新 |
targetMap | 全局依赖关系映射,存储所有依赖信息 |
reactive 的实现原理
Vue 3 使用 Proxy 对对象进行代理。其核心代码如下:
// packages/reactivity/src/reactive.ts
import { mutableHandlers } from './baseHandlers'
export function reactive(target: object) {
return createReactiveObject(target, false, mutableHandlers)
}
// createReactiveObject 实现
function createReactiveObject(target, isReadonly, baseHandlers) {
if (typeof target !== 'object') return target
const proxy = new Proxy(target, baseHandlers)
return proxy
}
关键点分析:
-
createReactiveObject会对传入的对象创建一个Proxy代理。 -
所有对象属性的读取和修改操作都通过
get和set拦截器进行处理。 -
读取操作会触发
track,用于依赖收集;写入操作会触发trigger,用于通知更新。
依赖收集(track)
依赖收集发生在 Proxy.get 中,用于记录哪个副作用函数(effect)正在访问哪个属性。
// baseHandlers.ts
function get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key) // 依赖收集
return result
}
// track.ts
const targetMap = new WeakMap()
export function track(target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let dep = depsMap.get(key)
if (!dep) {
dep = new Set()
depsMap.set(key, dep)
}
dep.add(activeEffect) // 添加依赖
}
简要流程:
-
在副作用函数执行时(如组件渲染),访问响应式对象属性。
-
触发
get,调用track。 -
将当前正在执行的
activeEffect保存到dep中。
响应式更新(trigger)
当响应式对象属性被修改时,会触发 set 拦截器,进而调用 trigger。
// baseHandlers.ts
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver)
trigger(target, key)
return result
}
// trigger.ts
export function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const dep = depsMap.get(key)
if (dep) {
dep.forEach(effectFn => effectFn())
}
}
简要流程:
-
修改属性时触发
set。 -
调用
trigger找到该属性所有依赖的副作用函数。 -
执行这些副作用函数,完成更新。
effect:连接响应式和副作用的桥梁
effect 是整个响应式系统的“桥梁”,负责注册副作用函数,使其能被响应式属性触发。
let activeEffect = null
export function effect(fn) {
const effectFn = () => {
activeEffect = effectFn
fn()
activeEffect = null
}
effectFn()
}
使用示例:
const state = reactive({ count: 0 })
effect(() => {
console.log('count is', state.count)
})
// 修改 state.count,会触发 effect 再次执行
state.count++
核心机制:effect 内访问了
state.count,于是count属性记录了这个 effect,当 count 改变时,这个 effect 会重新执行。
整体流程图
源码小结
-
Vue 使用 Proxy 动态拦截对象操作,做到“所见即所得”。
-
核心是
track和trigger两大系统,构成了依赖收集与更新通知机制。 -
effect将副作用函数与响应式数据关联起来,实现自动更新。
总结
Vue 的响应式系统实现看似简单,实则优雅高效。它通过 Proxy 实现了高度的可扩展性,通过 effect 与 track/trigger 实现了自动依赖追踪与更新机制。
理解其原理不仅可以帮助我们编写更高性能、更优雅的代码,也有助于我们在构建自定义 hooks、状态管理、组件库时得心应手。
3万+

被折叠的 条评论
为什么被折叠?



