VUE基础进阶(一):vue响应式原理

132 阅读2分钟

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,vue 会遍历 data 选项的属性,利用 Object.defineProperty 为属性添加 getter 和 setter 对数据的读取进行劫持(getter 用来依赖收集,setter 用来派发更新),并且在内部追踪依赖,在属性被访问和修改时通知变化。

每个组件实例会有相应的 watcher 实例,会在组件渲染的过程中记录依赖的所有数据属性(进行依赖收集,还有 computed watcher,user watcher 实例),之后依赖项被改动时,setter 方法会通知依赖与此 data 的 watcher 实例重新计算(派发更新),从而使它关联的组件重新渲染。

优点: 它使用基于依赖追踪的观察系统并且异步队列更新,所有的数据变化都是独立触发,除非它们之间有明确的依赖关系。

angularJs双向数据绑定的原理是脏检查机制

AngularJs 为 scope 模型上设置了一个 监听队列,用来监听数据变化并更新 view 。每次绑定一个东西到 view(html) 上时 AngularJs 就会往 watch 队列里插入一条watch,用来检测它监视的 model里是否有变化的东西。当浏览器接收到可以被angular context 处理的事件时,digest 循环就会触发。digest 会遍历所有的 watch。从而更新DOM。(当浏览器接收到可以被angular context处理的事件时,digest循环就会触发。digest将会遍历我们的watch,如果watch没有变化,这个循环检测就将停止,如果有至少一个更新过,这个循环就会再次触发,直到所有的watch都没有变化。这样就能够保证每个model都已经不会再变化。这就是脏检查(Dirty Checking)机制)

缺点: 当 watcher 越来越多时会变得越来越慢,因为作用域内的每一次变化,所有 watcher 都要重新计算。并且,如果一些 watcher 触发另一个更新,脏检查循环 (digest cycle)可能要运行多次。

相关面试题:

  • 聊聊 Vue 的双向数据绑定,Model 如何改变 View,View 又是如何改变 Model 的?

    可以用以上原理回答

  • Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?

    Object.defineProperty无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;(一般需要手动vue.set)

    Object.defineProperty只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy可以劫持整个对象,并返回一个新的对象。

    Proxy不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。