【Vue原理】依赖更新 - 源码版

写文章不容易,点个赞呗兄弟 专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧 研究基于 Vue版本 【2.5.17】闭包

若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧函数

【Vue原理】依赖更新 - 源码版 学习

若是对依赖收集彻底没有概念的同窗,能够先看我这篇白话版this

响应式原理 - 白话版 prototype

咱们已经讲过了 依赖收集code

【Vue原理】依赖收集 - 源码版之基本数据类型 blog

【Vue原理】依赖收集 - 源码版之引用数据类型 token

如今就要看依赖更新了哈哈哈,毕竟收集完是要更新的嘛get

其实依赖更新挺简单的,就是两步源码

修改属性值 通知保存的依赖进行更新 重点只须要看 Object.defineProperty 设置的set 函数,当给数据重赋新值的时候,天然会触发 set 函数,完成依赖更新

function defineReactive(obj, key, val) {   

    var dep = new Dep(); 
    var childOb = observe(val);   

    Object.defineProperty(obj, key, {

       get(){   
            ... 属性被读取,完成依赖收集            
            // 返回闭包值
            return val
       },

       set(newVal) {    
       
            // 值没有变化
           if (newVal ===val) return
           
           // 修改闭包值
           val = newVal;    
       
            // 若是属性已经存在过,设置新值的时候,会从新调用一遍
           childOb = observe(newVal);  
         
            // 触发更新
           dep.notify();    
       }    
    }); 
}

依赖更新重点就重在 通知更新

而通知更新的重点,只有一句话,【dep.notify】

因此,咱们重点去了解这句话,如何通知,如何更新

好的, dep 在第一篇讲过了

【Vue原理】依赖收集 - 源码版之基本数据类型

咱们知道,dep 主要是存储依赖的,再看一遍源码

var Dep = function Dep() {    

    this.subs = []; // 依赖存储器

};

// 遍历 subs ,逐个通知依赖,就是逐个调用 watcher.update
Dep.prototype.notify = function() {    

    var subs = this.subs.slice();    

    for (var i = 0, l = subs.length; i < l; i++) {

        subs[i].update();
    }
};

看过了源码,咱们知道了,原来通知更新是【遍历依赖存储器】,而后一个个【调用 watcher.update】

由于 subs 装的是 watcher,因此,subs[0].update 就是 watcher.update

因而问题又来了,watcher.update 是怎么就更新了???

function Watcher(vm, expOrFn) {    

    this.vm = vm;    

    // 保存传入的更新函数    
    this.getter = expOrFn;

    // 新建 watcher 的时候,当即执行更新函数
    this.get();
};



Watcher.prototype.get = function() {  

    // 执行更新函数
    this.getter.call(this.vm,this.vm);  

};

Watcher.prototype.update = function() {    
    this.get()
}

看到上面的源码

1Watcher 新建实例的时候,会保存传入的函数(这个函数会做为更新用)

2watcher 实例有 update 方法,做用是执行上一步保存的更新函数

那么 watcher 是何时开始建立的呢?

以页面 watcher 举例,探索整个实例构建的基本流程

公众号

function Vue(options) {    

    this._init(options);

}

Vue.prototype._init = function(options) {
    // ...处理组件选项等
    this.$mount()
}

Vue.prototype.$mount = function() {

    // ...解析template成redner函数保存

    /** 每一个实例新建一个watcher,

           而且利用watcher 保存更新函数 **/

    new Watcher(this,        

        // 这个函数是更新函数,传入watcher保存下来,用于后面页面初始化或者页面更新

        function() {
             /** ...调用保存的渲染函数生成VNode,

                          并生成DOM插入页面中**/
        }
    );
};

看上面的源码 和注释大概就能够很清楚了

从 【new Vue】 到 【vm._init】 初始化 到 【vm.$mount】 挂载到页面,整个流程就完整了

重点是清楚 watcher的更新函数

更新函数

咱们能够看到这个页面的更新函数,做用是调用 渲染函数,而后生成DOM节点插入页面中。

更新函数会传入Watcher ,而后被保存到 watcher 的实例中

“整个函数涉及的源码不少,可是这里一概而过”

因此,通知更新作了这些工做

一、直接调用 watcher.update,也就是从新调用给 watcher 保存的更新函数

二、更新更新函数就是执行渲染函数,而后读取实例最新的值(已被修改过的值),最后从新生成DOM 节点

三、DOM 节点 插入或替换页面,完成更新

画个通知流程图

公众号

公众号

相关文章
相关标签/搜索