Vue.js中的computed功能設計
1、關于computed的功能描述
computed
作為計算屬性其作用是描述響應式數據的復雜邏輯計算,當所依賴的響應式數據發(fā)生改變時計算屬性會重新計算,更新邏輯計算的結果。
有個體現計算屬性特點的便是比較計算屬性和方法的區(qū)別,比如我們需要計算兩個響應式數據的和
const obj = new reactive({foo: 1, bar: 2}) // 使用計算屬性獲取值 const value = computed(() => {obj.foo + obj.bar}) // 使用方法獲取值 const value = () => obj.foo + obj.bar
其區(qū)別為computed有緩存機制,當內部依賴的響應式數據沒有改變時則直接從緩存中獲取結果,而方法則每次都需要執(zhí)行。當依賴的響應式數據很多并且邏輯很復雜的時候那么計算屬性效率會比方法高很多。
2、計算屬性的lazy設計
對于計算屬性我們只有在需要值的時候才需要計算,而computed(getter)
以一個getter
作為參數,即每次計算屬性依賴的響應式數據改變的時候都需要重新執(zhí)行getter
,但是每次getter
的每一次執(zhí)行卻是不必要的,因為只有當獲取計算屬性的值時才運行getter
獲取值,所以對于getter
的計算需要懶惰執(zhí)行。
在上一章節(jié)中已經介紹了調度器的作用,所以我們只需要在調度器中加入一個lazy
的標記就行了
effect(() => { return obj.foo + obj.bar }, { // 調度器中設置lazy標記 lazy: true }) function effect(fn, options = {}) { const effectFn = () => { // 省略代碼 } effectFn.options = options effectFn.deps = [] // 如過有緩存標記則直接返回 if(options.lazy) return effectFn effectFn() } function computed(getter) { // 把getter作為一個副作用函數 const effectFn = effect(getter, { lazy: true, }) const obj = { // 只有當讀取到value時才會觸發(fā)effectFn get value() { return effectFn() } } return obj.value }
這樣只有我們在獲取計算屬性的value
時才會觸發(fā)副作用函數執(zhí)行,而不會在響應式數據改變時就直接執(zhí)行。
3、計算屬性的緩存
假設我們在上述代碼的設計基礎下有以下代碼
const sum = computed(() => obj.foo + obj.bar) console.log(sum.value) console.log(sum.value) console.log(sum.value)
此時effectFn
會接連執(zhí)行三次,但是每次的結果都是一樣的,因為計算屬性所依賴的obj.foo \obj.bar
的值并沒有改變,所以我們可以直接將計算的結果緩存下來。
function computed(getter) { // 用來緩存計算的結果 let value // 用于標記是否需要重新計算值 let dirty = true let effectFn = effect(getter, { lazy: true }) const obj = { get value() { // 如過需要重新計算值 if(dirty) { value = effectFn() dirty = false } return value } } return obj }
此時我們多次獲取sum.value
的值則不會每次都重新計算了,但是這樣寫有一個非常明顯的問題就是我們所依賴的響應式的值改變的時候不會重新計算,所以我們dirty
這個標記還需要和依賴的響應式數據聯系起來。具體做法是將dirty
放入調度器中,這樣每次響應式數據被改變的時候都會觸發(fā)調度器改變dirty
的值
function computed(getter) { // 用來緩存計算的結果 let value // 用于標記是否需要重新計算值 let dirty = true let effectFn = effect(getter, { lazy: true, // 當響應式數據修改時,觸發(fā)副作用函數時修改dirty的值 scheduler: () => { dirty = true } }) const obj = { get value() { // 如過需要重新計算值 if(dirty) { value = effectFn() dirty = false } return value } } return obj }
其實還有一個問題就是當計算屬性放入effect
形成嵌套時,我們改變obj
的值并不會觸發(fā)外層的effect
函數,即:
// 省略代碼...... const sum = computed(() => obj.foo + obj.bar) effect(() => { console.log(sum.value) })
當改變obj.foo/obj.bar
的值并不會輸出sum.value
的值。這是不符合應用場景的,在應用中當我們的計算屬性改變的時候頁面也會重新渲染。
整個問題分析一下就是effect
嵌套的問題,當內層的響應式數據只和getter
形成了聯系,和外層的副作用函數并沒有關系,而內部的value
并不是響應式數據還是懶執(zhí)行的,所以也就不會和外層的副作用函數產生聯系了,這里解決的方案就是直接手動將計算屬性的結果和外層副作用函數聯系起來。
function computed(getter) { let value let dirty = true const effectFn = effect(getter, { lazy: true, scheduler: () => { dirty = true // 計算屬性依賴的響應式數據發(fā)生改變時,手動觸發(fā)響應 trigger(obj, 'value') } }) const obj = { get value() { if(dirty) { value = effectFn() dirty = false } // 讀取value時手動追蹤 track(obj, 'value') return value } } return obj }
到此這篇關于Vue.js中的computed的設計的文章就介紹到這了,更多相關Vue.js computed內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Element-UI中<el-cascader?/>回顯失敗問題的完美解決
我們在使用el-cascader控件往數據庫保存的都是最后一級的數據,那如果再次編輯此條數據時,直接給el-cascader傳入最后一級的數據,它是不會自動勾選的,下面這篇文章主要給大家介紹了關于Element-UI中<el-cascader?/>回顯失敗問題的完美解決辦法,需要的朋友可以參考下2023-01-01解決VUE 在IE下出現ReferenceError: Promise未定義的問題
這篇文章主要介紹了解決VUE 在IE下出現ReferenceError: Promise未定義的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11vue - vue.config.js中devServer配置方式
今天小編就為大家分享一篇vue - vue.config.js中devServer配置方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10