vue computed 實現原理與 watch 對比


原理

<div id="app">
  {{num}}
  {{num1}}
</div>

var app = new Vue({
  el: '#app',
  data: {
    num: 1
  },
  computed: {
    num1 () {
      return this.num + 1;
    }
  }
});
console.log(app);

computed 本質是一個惰性求值的訂閱者。data 屬性的 Observer 掛在 _data 屬性下,而 computed 屬性掛在 _computedWatchers 下。而發布者 Dep 里存放了兩個訂閱者,而和computed相關的訂閱者,其實只做了一件事情,標記 dirty 為 true,等待 get 時再真正計算。

computed 內部實現了一個惰性的 watcher,也就是 _computedWatchers,_computedWatchers 不會立刻求值,同時持有一個 dep 實例。

其內部通過 this.dirty 屬性標記計算屬性是否需要重新求值

變更流程如下:

  1. 當 computed 的依賴的狀態發生改變時,就會通知這個惰性的 watcher。
  2. computed watcher 通過 this.dep.subs.length 判斷有沒有訂閱者,
    1. 有的話,會重新計算,然后對比新舊值,如果變化了,會重新渲染。 (Vue 想確保不僅僅是計算屬性依賴的值發生變化,而是當計算屬性最終計算的值發生變化時才會觸發渲染 watcher 重新渲染,本質上是一種優化。)
    2. 沒有的話,僅僅把 this.dirty = true。 (當計算屬性依賴於其他數據時,屬性並不會立即重新計算,只有之后其他地方需要讀取屬性的時候,它才會真正計算,即具備 lazy(懶計算)特性。)

watch

這是 computed 的 watcher 觀察者結構。特有的 lazy 為 true 代表 getter 時需要計算更新,注意 cb 只是一個空的函數,啥也不做,但是 expression 有值

Watcher {
    vm: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
    deep: false
    user: false
    lazy: true
    sync: false
    before: undefined
    cb: function noop(a, b, c) {}
    id: 1
    active: true
    dirty: false
    deps: (2) [Dep, Dep]
    newDeps: []
    depIds: Set(2) {3, 6}
    newDepIds: Set(0) {}
    expression: "len() {↵        return this.message.length↵      }"
    getter: ƒ len()
    value: 2
    __proto__: Object
}

這是 watch 的 觀察者結構,注意 user 為 true,expression 里沒有關鍵內容,但是 cb 里有,更新值的時候就是判定 user 為 true 時,調用 cb 獲取新值。

Watcher {
    vm: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
    deep: false
    user: true
    lazy: false
    sync: false
    before: undefined
    cb: function message() {
        this.full = this.message.join(',');
    }
    id: 2
    active: true
    dirty: false
    deps: (2) [Dep, Dep]
    newDeps: []
    depIds: Set(2) {3, 6}
    newDepIds: Set(0) {}
    expression: "message"
    getter: ƒ (obj)
    value: (2) ["a", "c", __ob__: Observer],
    __proto__: Object
}

與 watch 有什么區別

computed 計算屬性 : 依賴其它屬性值,並且 computed 的值有緩存,只有它依賴的屬性值發生改變,下一次獲取 computed 的值時才會重新計算 computed 的值。

watch 偵聽器 : 更多的是「觀察」的作用,無緩存性,類似於某些數據的監聽回調,每當監聽的數據變化時都會執行回調進行后續操作。

與 watch 運用場景的對比

需要在數據變化時執行異步或開銷較大的操作時,應該使用 watch,使用 watch 選項允許我們執行異步操作 ( 訪問一個 API ),限制我們執行該操作的頻率,並在我們得到最終結果前,設置中間狀態。這些都是計算屬性無法做到的。

當我們需要進行數值計算,並且依賴於其它數據時,應該使用 computed,因為可以利用 computed 的緩存特性,避免每次獲取值時,都要重新計算。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM