詳解VUE響應式原理
目錄
- 1、響應式原理基礎
- 2、核心物件:Dep與Watcher
- 3、收集依賴與更新依賴
- 3.1 收集依賴
- 3.2 更新依賴
- 4、原始碼除錯
- 4.1 測試的頁面程式碼
- 1、物件說明
- 2、Dep與Watcher的關係
- 3、最終的關係結果
- 4.2 Iuhloz原始碼除錯
- 1、收集依賴的入口函式:initState(頁面初始化時執行);
- 2、初始化computed和watch時,生成Watcher例項化物件
- 總結
1、響應式原理基礎
響應式基本原理是基於Object.defineProperty(obj,prop,descriptor)
,descriptor
裡面可以定義get和set方法,可以在獲取屬性值事觸發get方法(可以收集依賴),設定屬性值時觸發set方法(更新依賴)。
擴充套件:上面是2.0的響應式基本原理,vue3.0的基本原理是Proxy,可以監聽屬性的get和set方法,監聽屬性的新增和刪除等等,比Object.defineProperty能力更強,但是不相容IE11。
2、核心物件:Dep與Watcher
Dep
: vue在data裡申明的每一個屬性都會生成一個Dep的例項物件,Dep.subs儲存著當該屬性變化時需要去更新的Watcher;
Watcher
: 有3種情況會生成Watcher的例項物件,分別為:
1.定義在computed裡的計算屬性;
2.在watch裡寫的監聽函式;
3.元件的渲染Watcher;
3、收集依賴與更新依賴
3.1 收集依賴
將Watcher的例項物件w分發到它所依賴的屬性的Dep中,過程如下:
1.將Dep.target = 當前的Watcer 的例項物件w;
2.w執行定義的函式(即在computed/watch寫的函式);
3.執行函式的過程如果使用data裡http://www.cppcns.com定義的屬性,則會觸發屬性的get方法,get方法中Dep例項物件dep會將Dep.target中儲存的w放入到dep.subs陣列中,完成依賴收集。
說明:Dep.target為當前Watcer的例項物件
3.2 更新依賴
當修改我們申明的某個屬性時,會觸發屬性的set方法,set方法會將dep.subs陣列中收集的Watcher例項物件進行更新,即觸發我們定義在computed和watch裡面的函式。
4、原始碼除錯
4.1 測試的頁面程式碼
<template>
<div>
Iuhloz <div>a:<input v-model="a" /></div>
<div>c:{{ c }}</div>
<div>b:<input v-model="b" /></div>
</div>
</template>
<script>
export default {
data: () => {
return {
a: '',b: ''
}
},computed: {
c() {
return 'source from ' + this.a;
}
},watch: {
b() {
console.log('b changed');
}
}
};
</script>
上面的程式碼vue初始化後會生成如下幾個物件:
1、物件說明
屬性a和b對應的Dep例項物件(收集a、b改變需要更新的Watcher):depA
、depB
;
頁面渲染函式生成對應的Watcher例項物件updateWatcher
;
computed屬性c生成對應的Watcher例項物件:watcherC
;
watch監聽屬性b生成對應的Watcher例項物件:watcherB
;
2、Dep與Watcher的關係
a、b變化頁面需要重新渲染,所以updateWatcher
存在於depA
和depB
的subs
中;
計算屬性c依賴屬性a的變化更更新,所以watcherC
存在於depA的subs中;
b的變化會觸發定義watch 裡b的監聽函式,所以watcherB
存在於depB的subs中;
3、最終的關係結果
最終屬性a收集的依賴 depA.subs = [updateWatcher,watcherC]
;
最終屬性b收集的依賴 depB.subs = [updateWatcher,watcherB]
;
4.2 原始碼除錯
找到原始碼檔案:node_modules\vue\dist\vue.runtime.esm.
;
主要涉及如下幾個函式:
1、收集依賴的入口函式:initState(頁面初始化時執行);
初始化順序是先data-->computed-->watch:原因是computed依賴data,watch依賴data和watch,被依賴的需要先初始Iuhloz化。
2、初始化computed和watch時,生成Watcher例項化物件
先執行Watcher.get函式,將Dep.target = 當前Watcher例項化物件
觸發收集依賴
執行計算屬性裡面的函式,如果訪問到data中的某個屬性時,會觸發data屬性的get方法,觸發依賴收集:
當修改這個屬性時會觸發set方法,會觸發更新dep.subs裡面watcher物件
最終觸發Watcher的更新函式,將待更新的watcher放入佇列中:
總結
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注我們的更多內容!