深入浅出Vue响应式原理
Vue响应式原理
解析el模板中的指令,初始化模板,每一个使用订阅数据都会创建一个订阅者,添加到对应属性的dep对象的subs数组中,每当监听到属性改变,找到对应的dep对象,遍历所有的watcher对象,调用所有watcher对象的update方法,对view界面进行更新
解析html代码,谁在用属性,会调用属性的get方法,从而知道谁在使用数据,创建一个订阅者对象,添加到发布者数组里面,当数据发生改变时,会调用属性的set方法,此时需要发布者通知所有订阅者数据发生了改变,订阅者进行数据的更新
发布者,订阅者模式,使用数据会创建一个订阅者,每一个订阅者都会加入发布者数组,每当数据发生改变,发布者就会通知所有订阅者更新数据
- new Vue: 模板和属性
- Observer:劫持监听所有data属性,监听到数据变化时调用对应的dep对象notify()方法,遍历所有的watcher对象,调用watcher对象的update方法更改界面
- Dep:发布者,数据发生改变时,通知变化给数据的订阅者,调用watcher对象的update方法
- view更新视图 Watcher:订阅者,compile解析el模板,根据使用的数据所创建的订阅者,并会加入到对应的dep对象的subs数组中
- Compile:解析el模板生成对应的view
为什么vue不能监听数组的变化?
Vue2.0对于响应式数据的实现有一些不足:
- 无法检测数组/对象的新增
- 无法检测通过索引改变数组的操作。
Object.defineProperty是可以检测到通过索引改变数组
vue3.0为什么要用Proxy对象
Object.defineProperty对数据进行响应式操作
缺点:
-
无法检测到对象属性的新增或删除 由于js的动态性,可以为对象追加新的属性或者删除其中某个属性,这点对经过Object.defineProperty方法建立的响应式对象来说,只能追踪对象已有数据是否被修改,无法追踪新增属性和删除属性,这就需要额外的代码处理。
-
数组变化监听 vue2.x是通过代理数组原型,包装了一层数组的变异方法
-
get set 拦截器不能直接操作target对象
总结:
- Object.defineProperty 对数组和对象的表现一直,并非不能监控数组下标的变化,vue2.x中无法通过数组索引来实现响应式数据的自动更新是vue本身的设计导致的,不是 defineProperty 的锅。
- Object.defineProperty 和 Proxy 本质差别是,defineProperty 只能对属性进行劫持,所以出现了需要递归遍历,新增属性需要手动 Observe 的问题。
- Proxy 作为新标准,浏览器厂商势必会对其进行持续优化,但它的兼容性也是块硬伤,并且目前还没有完整的polifill方案。