Vue3 源码面试问题
Vue3 源码面试问题:副作用函数与 Trigger 触发更新
问题
Trigger 触发更新:在 set 或 deleteProperty 拦截器中调用 trigger 函数,通知所有依赖该属性的副作用函数重新执行,这其中的副作用是不是指的组件的 render 函数执行生成虚拟 dom?
解答
在 Vue3 的响应式系统中,副作用函数(effect) 是一个更广泛的概念,组件的 render 函数只是其中一种常见类型。让我详细解释:
副作用函数的定义
副作用函数是指:
- 会依赖响应式数据的函数
- 当依赖的响应式数据变化时,需要自动重新执行的函数
常见的副作用函数类型
-
组件的渲染函数(render)
- 这是最常见的副作用函数
- 当组件依赖的响应式数据变化时,
render函数会重新执行,生成新的虚拟 DOM - 然后通过 Diff 算法更新实际 DOM
-
watch监听的回调函数- 当监听的响应式数据变化时,执行对应的回调函数
- 例如:
watch(() => state.count, (newVal) => { console.log(newVal) })
-
computed计算属性的 getter 函数- 当计算属性依赖的响应式数据变化时,重新计算并缓存结果
- 例如:
const double = computed(() => state.count * 2)
-
开发者手动创建的
effect函数- 直接使用
effect()API 创建的自定义副作用函数 - 例如:
effect(() => { document.title = state.count })
- 直接使用
Trigger 触发更新的机制
当响应式数据发生变化时(set 或 deleteProperty 操作):
- 调用
trigger函数 trigger函数根据变化的属性,找到对应的dep(依赖集合)- 遍历
dep中的所有副作用函数,依次执行 - 不同类型的副作用函数会通过不同的调度器(scheduler)执行
源码中的实现
在 @vue/reactivity 源码中:
effect函数创建副作用函数并收集依赖track函数在访问响应式数据时收集依赖关系trigger函数在修改响应式数据时触发依赖更新- 组件的
render函数会被包装成一个副作用函数,在组件初始化时通过setupRenderEffect注册
结论
组件的 render 函数确实是一种副作用函数,但副作用函数的范围更广,包括 watch 回调、computed getter 以及自定义 effect 函数等。
trigger 函数触发的是所有依赖该属性的副作用函数,而不仅仅是组件的 render 函数。这是 Vue3 响应式系统的核心设计,确保了所有依赖响应式数据的逻辑都能自动更新。