vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

zane1發表於2019-03-02

Vue雙向資料繫結的核心和基礎api是Object.defineProperty,其內部真正參與資料雙向繫結流程的主要有Obderver、Dep和Watcher,基於defineProperty和釋出者訂閱者模式,最終實現資料的雙向繫結。那麼Obderver、Dep和Watcher是如何具體配合工作的呢?下面就來理一理。

看此文章之前你需要對vue的雙向資料繫結有一定的理解。若不瞭解可移步:vue.js原始碼解讀系列 – 雙向繫結具體如何初始化和工作

看到這裡就當你對雙向資料繫結已經有一定的理解:

提示:要看懂此篇文章你需要對vue的mvvm有一定的瞭解,並需要和專注的去理解,或者對照原始碼跟著走,不然就很難真的看懂。

在這裡把雙向資料繫結分為兩個流程:

1、收集依賴流程:

observe -> 
walk -> 
defineReactive -> 
get -> 
dep.depend() -> 
watcher.addDep(new Dep()) -> 
watcher.newDeps.push(dep) -> 
dep.addSub(new Watcher()) -> 
dep.subs.push(watcher)複製程式碼

依賴收集會經過以上流程,最終watcher.newDeps陣列中存放dep列表,dep.subs陣列中存放watcher列表。

為什麼要進行依賴收集?

new Vue({
    data(){
        return {
             name:`zane`,
             sex:`男`
        }
    }
})複製程式碼

有上面這個data,實際上頁面只使用到了name,並沒有使用age,根據Object.defineProperty的轉換,如果我們設定了this.sex=`女`,那麼Vue也會去執行一遍虛擬DOM的比較,這樣就無形的浪費了一些效能,因此才需要做依賴收集,介面用到了就收集,沒有用到就不收集。

我們跟著流程走來理一遍原始碼:

直接進入Object.defineProperty的get方法:

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

考驗你閉包能力的時候到了,這個dep物件就是一個閉包。記下來我們看看dep.depend()方法的實現。

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

先暫停一下,上面兩處都用到了 Dep.target ,我也說了它就是一個Watcher例項化物件,你是不是很想搞懂它到底在哪裡賦值的呢,不急請跟著我下面的程式碼看看。

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

搞懂了Dep.target等於一個Watche物件,現在繼續回到之前的思路看watcher.addDep做了什麼。

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

就這樣依賴收集的流程就走完了,是否感覺很繞。

總結:依賴收集最終在 watcher.newDeps 中push了閉包中傳過來的dep物件,在dep.subs中push了初始化Vue是簡歷的Watcher物件,這個物件的,this.getter = expOrFn,傳過來的expOrFn是後期資料更新頁面渲染的核心步驟,需要沉下心來好好去理理。

2、檢視更新流程:

set -> 
dep.notify() -> 
subs[i].update() -> 
watcher.run() || queueWatcher(this) -> 
watcher.get() || watcher.cb -> 
watcher.getter() -> 
vm._update() -> 
vm.__patch__()複製程式碼

檢視更新會經過以上流程,最終呼叫Vue的虛擬Dom diff過程實時更新介面檢視

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

vue.js原始碼- 剖析observer,dep,watch如何具體的實現資料雙向繫結

走到此處後面我就不去跟蹤了,後面會呼叫vm.__patch__ 方法,進而執行虛擬DOM的diff過程實時的更新介面。

總結:

要很好的理解vue的資料雙向繫結就要比較耐心,沉下心來慢慢理解,同時也需要對vue的原始碼有個大致的理解,不然你只會看的越來越煩躁越來越沒有信心。

vue很好的利用了Object.defineProperty方法的 get和set方法,訂閱者釋出者的設計思路,巧妙的組織程式碼,值得我們很深入的去學習和理解,從而促使我們更好的去使用它。謝謝尤大的無私奉獻,讓我們提高了生產力,把更多的精力花到業務邏輯中去。

原文地址:github.com/wangweiange…

相關文章