类别:vue / 日期:2022-08-26 / 浏览:225 / 评论:0

在初始化 Vue 的每个组件时,会对组件的 data 进行初始化,就会将由普通对象变成响应式对象,在这个过程中便会进行依赖收集的相关逻辑,如下所示:

function defieneReactive (obj, key, val){
    const dep = new Dep();...Object.defineProperty(obj, key, {
        ...
        get: function reactiveGetter () {
            if(Dep.target){
                dep.depend();...
            }
            return val
        }
        ...
    )}
}

以上只保留了关键代码,主要就是 const dep = new Dep()实例化一个 Dep 的实例,然后在 get 函数中通过 dep.depend() 进行依赖收集。(1)DepDep 是整个依赖收集的核心,其关键代码如下:

class Dep {
    static target;
    subs;
    constructor () {
        ...this.subs = []
     }
     addSub (sub) {
        this.subs.push(sub)
     }
     removeSub (sub) {
        remove(this.sub, sub)
     }
     depend () {
        if(Dep.target){
            Dep.target.addDep(this)
        }
     }
     notify () {
        const subs = this.subds.slice();
        for(let i = 0;i < subs.length; i++){
            subs[i].update()
        }
     }
}

Dep 是一个 class ,其中有一个关 键的静态属性 static,它指向了一个全局唯一 Watcher,保证了同一时间全局只有一个 watcher 被计算,另一个属性 subs 则是一个 Watcher 的数组,所以 Dep 实际上就是对 Watcher 的管理,再看看 Watcher 的相关代码 ∶

(2)Watcher

class Watcher {
    getter;
    ...
    constructor (vm, expression){
        ...
        this.getter = expression;this.get();
    }
    get () {
        pushTarget(this);
        value = this.getter.call(vm, vm)
        ...
        return value
    }
    addDep (dep){
        ...
        dep.addSub(this)
    }
    ...
} 
function pushTarget (_target) {
    Dep.target = _target   
}

Watcher 是一个 class,它定义了一些方法,其中和依赖收集相关的主要有 get、addDep 等。

(3)过程

在实例化 Vue 时,依赖收集的相关过程如下 ∶ 初 始 化 状 态 initState , 这 中 间 便 会 通 过 defineReactive 将数据变成响应式对象,其中的 getter 部分便是用来依赖收集的。初始化最终会走 mount 过程,其中会实例化 Watcher ,进入 Watcher 中,便会执行 this.get() 方法,

updateComponent = () => {
  vm._update(vm._render());
};
new Watcher(vm, updateComponent);

get 方法中的 pushTarget 实际上就是把 Dep.target 赋值为当前的 watcher。

this.getter.call(vm,vm),这里的 getter 会执行 vm._render() 方法,在这个过程中便会触发数据对象的 getter。那么每个对象值的 getter 都持有一个 dep,在触发 getter 的时候会调用 dep.depend() 方法,也就会执行 Dep.target.addDep(this)。刚才 Dep.target 已经被赋值为 watcher,于是便会执行 addDep 方法,然后走到 dep.addSub() 方法,便将当前的 watcher 订阅到这个数据持有的 dep 的 subs 中,这个目的是为后续数据变化时候能通知到哪些 subs 做准备。所以在 vm._render() 过程中,会触发所有数据的 getter,这样便已经完成了一个依赖收集的过程。

版权声明 : 本文未使用任何知识共享协议授权,您可以任何形式自由转载或使用。

评论区

发表评论 / 取消回复

必填

选填

选填

◎欢迎讨论,请在这里发表您的看法及观点。

«    2023年11月    »
12345
6789101112
13141516171819
20212223242526
27282930

最新留言