vue源码解读--依赖收集

目录导航

经过上一节(响应式的创建过程)分析,我们知道了data中数据的每一层都被我们通过Object.defineProperty架设了一层拦截,当我们去访问的时候会先执行了一些自己逻辑。那么现在有两个问题:什么时候会访问到data?拦截后做了什么?

\bullet 访问data中数据的时机

        \alpha -经过之前章节的分析,我们知道,每一个组件的加载过程都要经历一次mount,在mountComponent过程中定义了updateComponent函数并实例化一个渲染watcher,在其constructor中将updateComponent赋值给getter并调用了get方法

                \star 调用pushTarget

(该方法向dep上的静态属性添加了当前的渲染watcher,同时向targetStack里push了一位)

                            ~dep是我们说的"发布者",它将在适当的时机去向订阅者进行广播,而watcher其实就是它的订阅者

                            ~向targetStack中push,主要是因为组件的渲染是一次嵌套渲染的过程,它需要在每一次渲染完子组件后恢复到父组件

                \star 接着便调用getter即updateComponent方法

                            ~执行组件的render,将调用render.call,render其实就是我们在组件内部手写的render函数

(这里我们通过this.meta.msg进行了访问)

                \lceil 由于我们组件在init过程中已经为msg架设了拦截,故此时将进入msg的get方法\rfloor

                \star 接着执行popTarget,将target恢复为父组件

(这是因为js是单线程的,子组件结束后vue需要接着去执行父组件的渲染流程)

                            \star 最后执行cleanupDeps

(deps 、newDeps 、depIds 、newDepIds 都是在watcher实例化过程中定义的,这里是为了将某些watcher进行移除,减少不必要的更新。例如当结构中使用了v-if时,当其值为false时,我们就不需要也不应该再对其进行响应了)

                    ~那么为什么说将这些deps 、 newDeps 、 depIds 、 newDepIds更新一遍后下次就不会再进行响应了呢?这是因为,每次get的时候都会调用dep.depend方法,dep.depend又会调用watcher的addDep方法,在该方法中对这些值进行了保存(即:完成了订阅),同时调用dep.addSub将本次的watcher保存到dep中(即:完成收集),那么不需要订阅的自然需要去除

\bullet 拦截后做了什么

            我们在分析cleanupDeps时实际上已经大致说了拦截后做的事情,那就是去完成watch的收集保存到dep的subs上,以便于在设置key的时候能向watcher进行广播,同时完成对dep的订阅保存到watcher的deps 、 newDeps 、 depIds 、 newDepIds 上,以便在适当的时机取消对dep的订阅

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容