學習 vue 原始碼 響應式原理

2022-07-16 02:06:14 字數 2506 閱讀 9578

由於剛開始學習 vue 原始碼,而且水平有限,有理解或表述的不對的地方,還請不吝指教。

vue 主要通過 watcher、dep 和 observer 三個類來實現響應式檢視。另外還有乙個 scheduler 來進行排程,本次暫時不做討論。

watcher 和 dep 是訂閱者和發布者的關係,每個 watcher 可以訂閱多個 dep,而每個 dep 也可以被多個 watcher 訂閱。當 observer 監聽的資料發生改變時,相應的 dep 就會觸發其訂閱者 watcher 更新檢視。

下面通過乙個簡單的例子來說明其實現流程和原理:

頁面初始會顯示 "init" 字串,3秒鐘之後,會更新為 "changed" 字串。

為了便於理解,將整個流程分為三個階段:

初始化data,這個階段 vue 通過 observer 監聽 data 物件,並將普通的 somevar 屬性**為 get\set 屬性

初次掛載el,這個階段 vue 使用預設的 somevar 資料渲染檢視,並將 watcher 新增到 dep 的訂閱者列表

somevar 更改觸發檢視更新,這個階段 somevar 被賦予了新值,vue 根據 watcher 和 dep 的訂閱關係觸發檢視的更新

下面我們來逐步分析這三個階段的流程。

new vue(options) => vm._init(options) => initstate(vm) => initdata(vm) => observe(data) => new observer(data) => definereactive(data, key, value)

初始化操作會監聽 data 物件,對其每乙個屬性呼叫 definereactive() 方法,將其改造為響應式屬性,**如下(去掉了不影響表述主流程的**,以便能更清晰的抓住重點):

/**

* define a reactive property on an object.

*/export function definereactive (

obj: object,

key: string,

val: any

) , set: function reactivesetter (newval)

val = newval

dep.notify()}})

}

可以看到,當 get() 方法執行的時候,會呼叫 dep.depend() ;當 set() 方法執行時,會呼叫 dep.notify()。後面我們會看到這兩個方法的作用。

vm.$mount(el) => mountcomponent(vm, el) => new watcher(vm, updatecomponent) => watcher.get() => updatecomponent() => vm._update(vm._render())

vm._render() 呼叫 vm.$options.render() 方法生成 vnode,vm._update() 方法根據 vnode 對檢視做更新。

vm.$options.render() 方法是在 $mount() 方法中生成的,生成後的**如下:

(function() 

}, [_v("\n         " + _s(somevar) + "\n ")])

}})

可以看到,**中會使用到 vm.somevar 屬性,而該屬性最終會**到之前定義的響應式屬性上,從而呼叫其 get() 方法,進而呼叫 dep.depend() 方法將 watcher 新增到訂閱者列表。

dep.depend() => dep.target.adddep(dep) => dep.addsub(watcher) => dep.subs.push(watcher)

dep.subs 就是 dep 的訂閱者列表,通過這個流程,就建立起了 dep 和 watcher 之間的訂閱關係。

其中,dep.target 就是當前的 watcher,因為在 watcher.get() 方法執行時,有如下流程:

watcher.get() => pushtarget(watcher) => dep.target = watcher

3秒之後,vm.somevar 被賦予了新的值,從而最終會呼叫到響應式屬性的 set() 方法,進而呼叫 dep.notify(),觸發 watcher 更新檢視。

dep.notify() => watcher.update() => watcher.run() => watcher.get() => watcher.getter.call(vm, vm) == updatecomponent() => vm._update(vm._render())

watcher 的 getter() 方法就是第二階段 new watcher(vm, updatecomponent) 中的 updatecomponent 方法,可以看到,通過這個流程,檢視得到了更新。

以上就構成了乙個響應式檢視模型,其核心是利用 defineproperty() 方法將普通屬性轉換為帶有鉤子的 set\get 屬性,從而實現了資料監聽。

Vue 響應式原理 原始碼

整個函式結束,相當於初始化所有屬性和vue內建事件 如 emit 並且使所有屬性變為響應式。初始化所有option api 對其中的使用者自定義資料data 進行 observe 此函式用來新建乙個類observer的例項,類observer的constructor中用walk 函式進行遍歷每個屬性...

結合原始碼解析 vue響應式原理

vue響應式原理 在之前vue2.0中,vue的響應式原理主要是基於object.defineproperty進行資料劫持然後結合觀察者模式 發布訂閱模式 來實現資料的雙向繫結。function dep dep.prototype.notify function function sub x sub...

vue原始碼學習 響應式資料

vue原始碼學習 初始化data vue原始碼學習 響應式資料 在 vue原始碼學習 初始化data 一文中,知道了在new vue 時做了一系列初始化操作,其中在初始化data資料時,利用observe data,true 方法,對資料屬性進行了觀察。下面來具體看下是如何對data進行的觀察,從而...