【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 節點 插入或替換頁面,完成更新

畫個通知流程圖

公衆號

公衆號

相關文章
相關標籤/搜索