深入响应式原理
// 维持一个执行副作用的栈 const runningEffects = [] // 当前正在运行的副作用 const createEffect = fn => { // 将传来的 fn 包裹在一个副作用函数中 const effect = () => { runningEffects.push(effect) fn() runningEffects.pop() } // 立即自动执行副作用 effect() } createEffect(() => { sum = val1 + val2 })
Proxy 是一个对象,它包装了另一个对象,并允许你拦截对该对象的任何交互。
我们这样使用它:new Proxy(target, handler)
const dinner = { meal: 'tacos' } const handler = { get(target, property) { console.log('intercepted!') return target[property] } } const proxy = new Proxy(dinner, handler) console.log(proxy.meal) // intercepted! // tacos
使用 Proxy 的一个难点是 this 绑定。我们希望任何方法都绑定到这个 Proxy,而不是目标对象,这样我们也可以拦截它们。值得庆幸的是,ES6 引入了另一个名为 Reflect 的新特性,它允许我们以最小的代价消除了这个问题:
const dinner = { meal: 'tacos' } const handler = { get(target, property, receiver) { return Reflect.get(...arguments) } } const proxy = new Proxy(dinner, handler) console.log(proxy.meal) // tacos
使用 Proxy 实现响应性的第一步就是跟踪一个 property 何时被读取。我们在一个名为 track 的处理器函数中执行此操作,该函数可以传入 target 和 property 两个参数。
const dinner = { meal: 'tacos' } const handler = { get(target, property, receiver) { track(target, property) return Reflect.get(...arguments) } } const proxy = new Proxy(dinner, handler) console.log(proxy.meal) // tacos
这里没有展示 track 的实现。它将检查当前运行的是哪个副作用,并将其与 target 和 property 记录在一起。这就是 Vue 如何知道这个 property 是该副作用的依赖项。
最后,我们需要在 property 值更改时重新运行这个副作用。为此,我们需要在代理上使用一个 set 处理函数:
const dinner = { meal: 'tacos' } const handler = { get(target, property, receiver) { track(target, property) return Reflect.get(...arguments) }, set(target, property, value, receiver) { trigger(target, property) return Reflect.set(...arguments) } } const proxy = new Proxy(dinner, handler) console.log(proxy.meal) // tacos
现在,我们对 Vue 如何实现这些关键步骤有了答案:
1、当一个值被读取时进行追踪:proxy 的 get 处理函数中 track 函数记录了该 property 和当前副作用。
2、当某个值改变时进行检测:在 proxy 上调用 set 处理函数。
3、重新运行代码来读取原始值:trigger 函数查找哪些副作用依赖于该 property 并执行它们。
该被代理的对象对于用户来说是不可见的,但是在内部,它们使 Vue 能够在 property 的值被访问或修改的情况下进行依赖跟踪和变更通知。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

上一篇: petite-vue 快速上手
下一篇: 不要相信一个熬夜的人说的每一句话
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论