Vue是數據驅動視圖模式,數據變動後,會自動更新視圖。開發很便利,不要手動管理視圖更新。哪 Vue 是如何實現自動更新,也就是響應式的?vue
以原生 JS 爲例,數據變化了須要手動獲取 Dom 節點,而後使用相關 Api 去修改視圖git
而 Vue 數據變化後須要自動更新視圖,因此流程應該: 從圖能夠大體感覺到,響應式更新有兩個難點須要解決:代碼實現, 一共 373 行JS代碼,包含Watcher/Observer的簡單實現github
入口代碼:數據結構
new Vue({
el: '#app',
data() {
return {
message: 'hello'
}
},
render(h) {
return h('div', null, this.message)
},
})
複製代碼
渲染效果: 閉包
響應式更新:app
通常而言,對於基本類型的值是否變化,能夠對比先後值是否相同。對於引用類型是否有變化,則可能須要遞歸判斷屬性是否都一致。異步
在 Vue 中,組件數據 data 是 Object 類型的,這樣作的好處,我理解一是方便擴展屬性、二是爲了能方便對數據進行攔截、代理等。函數
針對 Object 類型的的數據,其相關key/value能夠經過 數據屬性/訪問器屬性 獲取。二者能夠是能夠互換的: 性能
數據屬性訪問簡單直觀,而訪問器屬性擴展性更好。在Vue種爲了監聽屬性變化,使用訪問器屬性 覆寫了 數據屬性。在Vue中定義的數據結構爲 ui
通過Vue解析處理後data
函數的值會存儲到
_data
私有屬性中:
Vue 也是藉助 Object.defineProperty 實現的:
function proxy(target, sourceKey, key) {
Object.defineProperty(target, key, {
enumerable: true,
configurable: true,
get() {
return target[sourceKey][key]
},
set(val) {
target[sourceKey][key] = val
}
})
}
複製代碼
藉助 getter/setter 便可感知到數據變化,而自動觸發視圖更新作準備
Vue視圖渲染的過程爲: 模板 + 數據 -> 虛擬Dom -> Diff ... Dom操做 -> 真實Dom(渲染到頁面中),這個過程能夠很天然的使用數據。但數據不只包含視圖展現數據、還會有一些視圖不須要數據,若是每次檢測到數據變化都從新執行一遍視圖的渲染,這樣可能形成極大的性能損耗。那如何才能識別哪些是視圖所依賴的數據呢?
數據是在函數中引用的,故能夠在訪問數據時,記錄當前執行的函數便可,整個思路以下:
簡單實現步驟爲:訪問器,執行閉包的保存的render函數,觸發視圖從新渲染 在Vue中實現,爲了更好的性能(異步渲染,可能多處修改屬性值)、更好的擴展性(屬性可能多處被引用,須要自動更新、以及支持watch、compute屬性等),引入了 watcher/observer/dep 來實現依賴收集以及自動更新。
經過更多的分層,實現更好的擴展性。代碼的思路:經過 defineProperty 對數據屬性進行攔截,再攔截的基礎上 基於 JS 單線程原理進行依賴收集,數據變動時觸發視圖的從新渲染。