• Vue源码之-----computed


    computed属性的意义:如果组件渲染生成虚拟节点的过程中,需要通过一个方法计算得到某个返回值,可以在渲染的时候直接调用这个方法,但是如果这次的渲染不是由方法所依赖的变量值的变化导致的,那么再计算一次就没有必要。

    computed的每个属性(假设为c)会被挂载在vm上,为c新建一个对应的watcher,重写c的get方法如下

    function computedGetter () {
                var watcher = this._computedWatchers && this._computedWatchers[key];
                if (watcher) {
                    if (watcher.dirty) {
                        watcher.evaluate();
                    }
                    if (Dep.target) {
                        watcher.depend();
                    }
                    return watcher.value
                }
            }

    这里的watcher在new的时候,其dirty=lazy=true,所以组件在创建周期渲染生成虚拟节点的时候,要获取c的值,到这里发现dirty为true,调用watcher的evaluate方法

    Watcher.prototype.evaluate = function evaluate () {
            this.value = this.get();
            this.dirty = false;
        } ;

    watcher的get方法调用的时候,先把自己入栈,用vm调用watcher的getter方法,这里的getter方法就是c指向的那个方法,vm调用getter方法的时候,计算c的值,就会调用所有c所依赖的属性(简称d)的get方法,

    那么就会收集watcher(因为之前已经defineReacive(data)了)。同时在evaluate方法中,会把dirty设置为false,因为此时value的数据是全新的可用的。

    注意在computedGetter方法中,evaluate方法后面,还有一句if (Dep.target) { watcher.depend(); },因为此时c对应的watcher在evaluate方法完成后会出栈,之前栈顶的watcher会暴露,注意此时处于组件的创建周期中,这次的渲染是在vm.$mount--->

    new renderWatcher中,因为renderWatcher的lazy为false,new的最后会调用watcher.get()方法,renderWatcher入栈,调用watcher.getter方法(也就是vm._update(vm._render(), hydrating);)这个时候调用的render方法,所以computedWatcher出栈后

    栈顶的是renderWatcher,watcher.depend()这一句就是将收集computedWatcher的那些属性的get方法再收集一次renderWatcher。这种情形也就是为什么Dep和watcher要设计成你中有我我中有你的原因之一。

    注意此时c所依赖的属性的get方法既收集了computedWatcher,又收集了renderWatcher。

    到现在为止,组件的创建周期完成,当操作页面,有reactive属性的set方法被调用,发生组件重新渲染,进入更新周期的时候,分两种情况

    第一,这个reactive属性被c所依赖,那么它的set方法被调用会导致computedWatcher的update方法被调用,因为lazy为true,所以直接设置dirty为true,并不computedWatcher被放入异步微任务队列。

    而renderWatcher的的update方法会进入异步微任务队列,然后引起组件的重新渲染,在这个过程中,调用c的get方法,调用上面说的重写的computedGetter方法会发现watcher.dirty为true(宏任务中完成,所以时间早于微任务),

    所以通过evaluate方法重新计算一次watcher.value,返回。这个是符合逻辑的,因为c所依赖的属性改变了。

    第二种情况,就是引发这次重新渲染的属性并没有被c所依赖,那么它并没有收集computedWatcher,只有renderWatcher,那么render的时候获取c的属性,调用computedGetter方法的时候发现dirty为false,直接获取watcher.value而不是调用evaluate

    重新计算一次。

  • 相关阅读:
    手机浏览器跳转APP
    js识别用户设备是移动端手机时跳转到手机网站
    input文字颜色、光标颜色
    vue和微信小程序的区别、比较
    vue-router query和params传参(接收参数),$router、$route的区别
    vue父子组件、兄弟组件之间的通信和访问
    利用Everything开启http服务测试移动端浏览器环境
    Vue基础知识简介
    关于Vue的一些小技巧
    Flume环境安装
  • 原文地址:https://www.cnblogs.com/chuliang/p/10731488.html
Copyright © 2020-2023  润新知