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