现代前端框架有两种方式侦测变化,一种是pull一种是push
pull: 其代表为React,我们可以回忆一下React是如何侦测到变化的,我们通常会用setStateAPI显式更新,然后React会进行一层层的Virtual Dom Diff操作找出差异,然后Patch到DOM上,React从一开始就不知道到底是哪发生了变化,只是知道「有变化了」,然后再进行比较暴力的Diff操作查找「哪发生变化了」,另外一个代表就是Angular的脏检查操作。
push: Vue的响应式系统则是push的代表,当Vue程序初始化的时候就会对数据data进行依赖的收集,一但数据发生变化,响应式系统就会立刻得知,因此Vue是一开始就知道是「在哪发生变化了」,但是这又会产生一个问题,如果你熟悉Vue的响应式系统就知道,通常一个绑定一个数据就需要一个Watcher,一但我们的绑定细粒度过高就会产生大量的Watcher,这会带来内存以及依赖追踪的开销,而细粒度过低会无法精准侦测变化,因此Vue的设计是选择中等细粒度的方案,在组件级别进行push侦测的方式,也就是那套响应式系统,通常我们会第一时间侦测到发生变化的组件,然后在组件内部进行Virtual Dom Diff获取更加具体的差异,而Virtual Dom Diff则是pull操作,Vue是push+pull结合的方式进行变化侦测的.
总结
这个要从vue1开始说起,vue1的时候,使用的是全响应式的模式,数据更新非常之快,但是当项目大了后,就会出现一个问题,就是太多Watcher了,这样会存在严重的性能问题。随后,尤大就进行了改版,晋升vue2后,减少了Watcher的使用,使用的策略是一个组件一个Watcher。如果是一个组件一个Watcher的话,那么一个组件的内部data中会存在多个key,如果当这些key发生变化后,无法确定是那个key发生了改变,则这个时候就引进了diff算法,进行新旧dom比较,等出哪里发生了变化,从而进行更新操作。