一、把你了解的vue响应式原理解释一下
首先了解vue中的三个核心类:
1.observer:给对象的属性添加getter和setter,用于以来收集和派发更新。
2.dep:用于收集当前响应式对象的依赖关系,每个响应式对象都有一个dep实例。dep.subs = watcher[]。当数据发生变更的时候,会通过dep.notify()通知各个watcher。
3.watcher:观察者对象,render watcher,computed watcher,user watcher。
* 依赖收集
1.initState,对computed属性初始化时,会触发computed watcher 依赖收集。
2.initState,对监听属性初始化的时候,触发的user watcher 依赖收集。
3.render,触发render watcher依赖收集。
* 派发更新
Object.defineProperty。
1.组件中对响应的数据进行了修改,会触发setter逻辑。
2.dep.notify()
3.遍历所有subs,调用每一个watcher的update方法。
总结原理:
当创建vue实例时,vue会遍历data里的属性,Object.defineProperty 为属性添加getter和setter对数据的读取进行劫持。
getter:依赖收集
setter:派发更新
每个组件的实例都会有对应的watcher实例。
二、计算属性的实现原理
computed watcher,计算属性的监听器。
computed watcher 持有一个dep实例,通过dirty属性标记计算属性是否需要重新求值。
当computed的依赖值改变后,就会通知订阅的watcher进行更新,对于computed watcher 会将dirty属性设置为true,并且进行计算属性方法的调用。
1.computed 所谓的缓存是指什么?
计算属性是基于它的响应式依赖进行缓存的,只有依赖发生改变的时候,才会重新求值。
2.那computed缓存存在的意义是什么?或者说你经常在什么时候使用?
比如计算属性方法内部操作非常的耗时,遍历一个极大的数组,计算一次可能要耗时1s。
3.没有经过data初始化的数据,只在computed中变化,页面是监听不到数据变化的。
三、Vue.nextTick 的原理
vue是异步执行dom更新的,一旦观察到数据的变化,把同一个event loop中观察数据变化的watcher推送进这个队列。
在下一次事件循环时,Vue清空异步队列,进行dom的更新。
Promise.then > MutationObserver -> setImmediate > setTimeout.
vm.someData = 'new value',dom并不会马上更新,而是在异步队列被清除时才会更新dom。
宏任务 -> UI render -> 宏任务
一般什么时候用到nextTick呢?
在数据变化后要执行某个操作,而这个操作依赖因你数据改变而改变的dom,这个操作应该被放到vue.nextTick回调中。