页面dom操作方式:
(1).直接dom节点操作,我们命令什么,她就做什么 (js和jq这种方式)
(2).输入数据状态变化,输入视图,无需观察他是否做了什么操作(vue和react)
系统数据变化分为两种:
第一种是系统不可感知数据变化,典型框架react和angular,他们不知道数据什么时候变了,但是它们师徒是什么时候去更新的呢?比如react就是通过setState发信号告诉系统可能数据变化了,然后通过virtual dom diff去渲染视图,angular则是通过脏检查流程,遍历对比
第二种是系统可感知数据变化 典型的框架是vue,通过观察者模式,使用Observable (可观察对象),Observer (观察者)(或者是watcher)去订阅(比如视图渲染这一类,其实也可以当成一个观察者去订阅数据了,后面会提到),系统是可以很准确知道哪里数据变了的,从而也就能实现视图更新渲染。
上者系统不可感知数据变化,粒度粗,有时候还得手动优化(比如pureComponet和shouldComponentUpdate)去跳过一些数据不会更新的视图从而提升性能
下者系统可感知数据变化,粒度细,但是绑定大量观察者,有大量的依赖追踪的内存开销所以这里也就终于提到本文的主角Vue2,它采用了折中粒度的方式,粒度到组件级别上,由watcher订阅数据,当数据变化我们可以得知哪个组件数据变了,然后采用virtual dom diff的方式去更新相应组件。
数据响应原理
object.defineProperty
vue数据响应的核心使用了object.defineProperty方法(IE9+)在对象中定义属性或者修改属性,其中存取描述符很关键的就是get和set,提供给属性getter和setter方法可以看下面例子,我们拦截到了数据获取以及设置
顺便提到那个小细节的问题app.message如何拿到vue data中的message?其实也是跟Object.defineProperty有关
Vue在初始化数据的时候会遍历data代理这些数据
proxy这个方法是干什么的?
其实就是用Object.defineProperty多加了一层的访问
因此我们就可以用app.message访问到app.data.message
也算个Object.defineProperty小应用吧
讲完这语法的核心层面得知了如何知道数据发生变化,但是响应,是还有回应的,接下来来谈下Vue是如何实现数据响应的?
其实就是解决下面的问题,如何实现$watch?
观察者模式(Observer, Watcher, Dep)
Vue实现响应式有三个很重要的类,Observer类,Watcher类,Dep类
我这里先笼统介绍一下(详细可见源码英文注解)
- Observer类主要用于给Vue的数据defineProperty增加getter/setter方法,并且在getter/setter中收集依赖或者通知更新
- Watcher类来用于观察数据(或者表达式)变化然后执行回调函数(其中也有收集依赖的过程),主要用于$watch API和指令上
- Dep类就是一个可观察对象,可以有不同指令订阅它(它是多播的)
观察者模式,跟发布/订阅模式有点像
但是其实略有不同,发布/订阅模式是由统一的事件分发调度中心,