computed源码浅谈

1-什么时候初始化?

function Vue(){
    ... 其他处理
    initState(this)

    ...解析模板,生成DOM 插入页面

}



function initState(vm) {    

    var opts = vm.$options;    

    if (opts.computed) { 

        initComputed(vm, opts.computed); 

    }

    .....

}

 

你调用 Vue 创建实例过程中,会去处理各种选项,其中包括处理 computed

处理 computed 的方法是 initComputed

function initComputed(vm, computed) {    

    var watchers = vm._computedWatchers = 

            Object.create(null);    

    for (var key in computed) {        

        var userDef = computed[key];        

        var getter = 

            typeof userDef === 'function' ? 

                userDef: userDef.get;      



        // 每个 computed 都创建一个 watcher

        // watcher 用来存储计算值,判断是否需要重新计算

        watchers[key] = 

        new Watcher(vm, getter, { 

             lazy: true 

        });        

        

        // 判断是否有重名的属性

        if (! (key in vm)) {
            defineComputed(vm, key, userDef);
        }
    }
}

 

initComputed 这段代码做了几件事

1、每个 computed 配发 watcher

2、defineComputed 处理

3、收集所有 computed 的 watcher

好的,这三件事,一件一件说哈

 

4、每个 computed 配发 watcher

computed 到底和 watcher 有什么猫腻呢?

5、保存 computed 计算函数 2、保存计算结果 3、控制缓存计算结果是否有效

看下 Watcher 源码构造函数

function Watcher(vm, expOrFn, options) {    

    this.dirty = this.lazy = options.lazy;    

    this.getter = expOrFn;    

    this.value = this.lazy ? undefined: this.get();

};
new Watcher(vm, getter, { lazy: true })

 

watcher.value 存放计算结果,但是这里有个条件,因为 lazy 的原因,不会新建实例并马上读取值

这里可以算是 Vue 的一个优化,只有你再读取 computed,再开始计算,而不是初始化就开始计算值了

computed 新建 watcher 的时候,传入 lazy

没错,作用是把计算结果缓存起来,而不是每次使用都要重新计算

而这里呢,还把 lazy 赋值给了 dirty,为什么呢?

因为 lazy 表示一种固定描述,不可改变,表示这个 watcher 需要缓存

而 dirty 表示缓存是否可用,如果为 true,表示缓存脏了,需要重新计算,否则不用

dirty 默认是 false 的,而 lazy 赋值给 dirty,就是给一个初始值,表示 你控制缓存的任务开始了

所以记住,【dirty】 是真正的控制缓存的关键,而 lazy 只是起到一个开启的作用

具体,怎么控制缓存,下面会说

defineComputed 处理

function defineComputed(

    target, key, userDef

) {    

    // 设置 set 为默认值,避免 computed 并没有设置 set

    var set = function(){}      
    //  如果用户设置了set,就使用用户的set

    if (userDef.set) set = userDef.set   



    Object.defineProperty(target, key, {        

        // 包装get 函数,主要用于判断计算缓存结果是否有效

        get:createComputedGetter(key),        

        set:set

    });
}

1、使用 Object.defineProperty 在 实例上computed 属性,所以可以直接访问

2、set 函数默认是空函数,如果用户设置,则使用用户设置

3、createComputedGetter 包装返回 get 函数

function createComputedGetter(key) {    

    return function() {        

        // 获取到相应 key 的 computed-watcher

        var watcher = this._computedWatchers[key];        

        // 如果 computed 依赖的数据变化,dirty 会变成true,

                    从而重新计算,然后更新缓存值 watcher.value

        if (watcher.dirty) {
            watcher.evaluate();

        }        

        // 这里是 月老computed 牵线的重点,让双方建立关系

        if (Dep.target) {
            watcher.depend();

        }        

        return watcher.value

    }
}

 自此,讲新的数据返回

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值