蝦米帶你輕鬆搞定Vuejs 系列

(十五)Vue.js 依賴收集原理

一週沒有整理筆記了,今天繼續。前邊一節筆記記錄了vue.js的響應式系統的內部機制原理,今天我們整理一下響應式系統的依賴收集。

什麼是依賴收集

直接描述術語可能有點唐突。我們在這裏寫2個小例子,來加深一下代碼理解,再來解釋依賴收集。示例一:

 

 

初始化的html結構和初始化的data現在已經有了,這個時候發現address這個屬性並沒有在html結構中出現。接下來我們動態修改data中的address屬性的值。

我們看一下vue的內部數據變成了什麼,不妨看一下。

這裏我們修改了data中的address的數據,但是因爲視圖中不確定需要用到address,所以我們並不需要觸發上篇筆記中的cb 方法來更新視圖,簡單的說如果這裏觸發了cb 方法,說明你的邏輯是不正確的。可能大家還是不清楚,再來一個示例,假如有一個全局對象,我們會在多個Vue對象中用到它並展示。示例二:

最後執行全局全局屬性的修改,這裏通過數據看不出來,這裏需要分析內部,通過通知test1、test2兩個vm實例進行視圖的更新,依賴收集會讓 name 屬性這個數據知道,也就實現了倆個地方依賴全局數據,全局詩句變化時候需要通知各自的視圖。

最終我們形成數據與視圖的一種對應關係,我們簡單畫一下:

 

可是我發現我還是不夠清晰。怎麼又多了一個Dep呢?我再來探索一下Dep或者說依賴收集怎麼實現的。

 

Dep(defineProperty)

首先,我先實現一個簡單的訂閱者Dep,它是用來存放Watcher對象,也就是我們說的觀察者對象。

解釋一下這段代碼。主要是做了2件事情:

  • 調用addSub方法添加一個當前Dep對象的Watcher訂閱操作
  • 調用notify方法通知當前Dep對象的subs中的所有Watcher觸發更新

 

Watcher(觀察者)

這段代碼很簡單,這裏不多說了。

 

依賴收集

接下來我們修改一下 defineReactive 以及 Vue 的構造函數,來完成依賴收集。

我們在閉包中增加了一個 Dep 類的對象,用來收集 Watcher 對象。在對象被「讀」的時候,會觸發 reactiveGetter 函數把當前的 Watcher 對象(存放在 Dep.target 中)收集到 Dep 類中去。之後如果當該對象被「寫」的時候,則會觸發 reactiveSetter 方法,通知 Dep 類調用 notify 來觸發所有 Watcher 對象的 update 方法更新對應視圖。

 

 

 

總結

首先在 observer 的過程中會註冊 get 方法,該方法用來進行依賴收」。在它的閉包中會有一個 Dep 對象,這個對象用來存放 Watcher 對象的實例。其實依賴收集的過程就是把 Watcher 實例存放到對應的 Dep 對象中去。get 方法可以讓當前的 Watcher 對象(Dep.target)存放到它的 subs 中(addSub)方法,在數據變化時,set 會調用 Dep 對象的 notify 方法通知它內部所有的 Watcher 對象進行視圖更新。

 

這是 Object.defineProperty 的 set/get 方法處理的事情,那麼依賴收集的前提條件還有兩個:

  • 觸發 get 方法;
  • 新建一個 Watcher 對象。

這個我們在 Vue 的構造類中處理。新建一個 Watcher 對象只需要 new 出來,這時候 Dep.target 已經指向了這個 new 出來的 Watcher 對象來。而觸發 get 方法也很簡單,實際上只要把 render function 進行渲染,那麼其中的依賴的對象都會被讀取,這裏我們通過打印來模擬這個過程,讀取 test 來觸發 get 進行依賴收集。

 

本筆記介紹了依賴收集的過程,配合之前的響應式原理,已經把整個響應式系統介紹完畢了。其主要就是 get 進行依賴收集。set 通過觀察者來更新視圖,配合下圖仔細捋一捋,相信一定能搞懂它!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章