寫文章不容易,點個讚唄兄弟 專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧 研究基於 Vue版本 【2.5.17】閉包
若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧函數
若是對依賴收集徹底沒有概念的同窗,能夠先看我這篇白話版this
響應式原理 - 白話版 prototype
咱們已經講過了 依賴收集code
【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 在第一篇講過了
咱們知道,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 節點 插入或替換頁面,完成更新
畫個通知流程圖