-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第310题(2020-09-23):说说 vue 如何收集依赖的? #313
Comments
Vue实例在初始化时,可以接受以下几类数据:
Vue 根据实例化时接受的数据,在将数据和模板转化成DOM节点的同时,分析其依赖的数据。在特定数据改变时,自动在下一个周期重新渲染DOM节点 本文主要分析Vue是如何进行依赖收集的。 Vue中,与依赖收集相关的类有:
对初始化数据的处理对于一个Vue组件,需要一个初始化数据的生成函数。如下:
Vue为数据中的每一个key维护一个订阅者列表。对于生成的数据,通过Object.defineProperty对其中的每一个key进行处理,主要是为每一个key设置get, set方法,以此来为对应的key收集订阅者,并在值改变时通知对应的订阅者。部分代码如下:
每一key都有一个订阅者列表 const dep = new Dep() 在为key进行赋值时,如果值发生了改变,则会通知所有的订阅者 dep.notify() 在对key进行取值时,如果Dep.target有值,除正常的取值操作外会进行一些额外的操作来添加订阅者。大多数时间里,Dep.target的值都为null,只有订阅者在进行订阅操作时,Dep.target才有值,为正在进行订阅的订阅者。此时进行取值操作,会将订阅者加入到对应的订阅者列表中。 订阅者在进行订阅操作时,主要包含以下3个步骤:
在执行订阅操作后,订阅者会被加入到相关key的订阅者列表中。 针对对象和数组的处理如果为key赋的值为对象:
如果为key赋的值为数组:
对模板的处理Vue将模板处理成一个render函数。需要重新渲染DOM时,render函数结合Vue实例中的数据生成一个虚拟节点。新的虚拟节点和原虚拟节点进行对比,对需要修改的DOM节点进行修改。 订阅者订阅者在初始化时主要接受2个参数getter, callback。getter用来计算订阅者的值,所以其在执行时会对订阅者所有需要订阅的key进行取值。订阅者的订阅操作主要是通过getter来实现。 部分代码如下:
主要步骤:
此后,订阅者在依赖的key的值发生变化会得到通知。获得通知的订阅者并不会立即被触发,而是会被加入到一个待触发的数组中,在下一个周期统一被触发。 订阅者在被触发时,会执行getter来计算订阅者的值,如果值改变,则会执行callback. 负责渲染DOM的订阅者 部分代码如下:
vm._watcher = new Watcher(vm, updateComponent, noop) 此订阅者在初始化时就会进行订阅操作。实例化时传入的getter为updateComponent。其中的vm._render()在执行时一定会对所有依赖的key进行取值,能完成对依赖的key的订阅。同时vm._update()完成了第一次DOM渲染。当前依赖的key的值发生变化,订阅者被触发时,作为getter的updateComponent会重新执行,重新渲染DOM。因为getter返回的值一直为undefined,所以此订阅者中的callback并没有被用到,于是传入了一个空函数noop作为callback 对computed的处理通过computed可以定义一组计算属性,通过计算属性可以将一些复杂的计算过程抽离出来,保持模板的简单和清晰。 代码示例:
在定义一个计算属性时,需要定义一个key和一个计算方法。 Vue在对computed进行处理时,会为每一个计算属性生成一个lazy状态的订阅者。普通的订阅者在实例化和触发时会执行getter来计算自身的值和进行订阅操作。而lazy状态的订阅者在上述情况下只会将自身置为dirty状态,不进行其它操作。在订阅者执行自身的evaluate方法时,会清除自身的dirty状态并执行getter来计算自身的值和进行订阅。 Vue在为计算属性生成订阅者时的示例代码如下:
Vue 在自身实例上为指定key定义get方法,使可以通过Vue实例获取计算属性的值。 部分代码如下:
在对计算属性定义的key进行取值时,会首先获取之前生成好的订阅者。只有订阅者处于dirty状态时,才会执行evaluate计算订阅者的值。所以为计算属性定义的计算方法只有在对计算属性的key进行取值并且计算属性依赖的key曾经改变时才会执行。 假如对上文定义的计算属性key1进行取值
订阅计算属性值的变化计算属性的key不会维护一个订阅者列表,也不能通过计算属性的set方法在触发所有订阅者。(计算属性不能被赋值)。一个订阅者执行订阅操作来订阅计算属性值的变化其实是订阅了计算属性依赖的key的值的变化。 在计算属性的get方法中
例如:
对watch的处理Vue实例化时可以传入watch对象,来监听某些值的变化。 例如:
Vue 会为watch中的每一项生成一个订阅者。订阅者的getter通过处理字符串得到。如'a.b.c'会被处理成
处理字符串的源码如下:
订阅者的callback为定义watch时传入的监听函数。当订阅者被触发时,如果订阅者的值发生变化,则会执行callback。callback执行时会传入变化后的值,变化前的值作为参数。 |
No description provided.
The text was updated successfully, but these errors were encountered: