深入理解Vue3 computed
在模板里寫(xiě)一行 {{ sum }},背后卻藏著「惰性求值 + 精準(zhǔn)依賴(lài)收集 + 臟檢查緩存」的三重魔法。本文帶你鉆進(jìn)源碼,拆解 computed 如何決定「何時(shí)算、何時(shí)不、為何不能異步」。
一、使用方法
const state = reactive({ a: 1, b: 2 })
const sum = computed(() => state.a + state.b)
console.log(sum.value) // 3
state.a = 10
console.log(sum.value) // 12
看似普通,但注意兩點(diǎn):
- 只讀:sum 不是函數(shù),而是一個(gè)「帶緩存的 getter」。
- 懶執(zhí)行:直到第一次讀取
value,計(jì)算函數(shù)才真正跑一遍。
二、緩存機(jī)制:dirty 標(biāo)志位
源碼核心只有兩行狀態(tài)機(jī):
let value: any let dirty = true
- dirty 為 true → 需要重新計(jì)算
- dirty 為 false → 直接返回舊值
首次讀取 sum.value 時(shí),dirty 從 true 變?yōu)?false,并把結(jié)果存入 value。
當(dāng)依賴(lài)的響應(yīng)式數(shù)據(jù)變化,調(diào)度器把 dirty 重新置為 true,但不會(huì)立即計(jì)算,而是等待下一次讀取。
這就是「緩存」的本質(zhì):用 1 bit 的布爾值換一次昂貴的計(jì)算。
三、依賴(lài)收集:effect 包裹 getter
computed 的計(jì)算函數(shù)被 effect 包裝成副作用:
const effectFn = effect(getter, {
lazy: true,
scheduler() {
dirty = true
trigger(obj, TriggerOpTypes.SET, 'value')
}
})
lazy: true阻止首次執(zhí)行,實(shí)現(xiàn)惰性求值。scheduler在依賴(lài)變化時(shí)只打標(biāo)記,不立即重算,確保緩存語(yǔ)義。
當(dāng)模板讀取 sum.value,track 把當(dāng)前渲染副作用注冊(cè)到 computed 的依賴(lài)圖;當(dāng) state.a 變化,trigger 通知渲染器重新執(zhí)行,渲染器再去讀 sum.value,此時(shí)才真正觸發(fā)計(jì)算。
四、為什么拒絕異步?
設(shè)想一個(gè)異步 computed:
const asyncSum = computed(async () => {
const res = await fetch('/api/sum?a=' + state.a)
return res.json()
})
問(wèn)題立刻暴露:
緩存無(wú)法兌現(xiàn)
第一次讀取返回一個(gè)
Promise,第二次讀取依賴(lài)并未變化,但緩存里存的是 Promise,無(wú)法直接返回結(jié)果。渲染時(shí)數(shù)據(jù)缺位
模板在渲染階段需要同步值,異步導(dǎo)致視圖出現(xiàn)空檔或閃爍。
依賴(lài)追蹤混亂
異步完成時(shí)間不確定,期間若依賴(lài)再次變化,無(wú)法確定哪一次結(jié)果是最新。
Vue 官方給出的替代方案是 watch + ref:
const asyncSum = ref(0)
watch(state, async () => {
asyncSum.value = await fetch('/api/sum?a=' + state.a).then(r => r.json())
})
watch 不緩存、不阻塞渲染,天然適合異步副作用。
五、可寫(xiě) computed:緩存 + setter 的雙通道
const fullName = computed({
get() { return firstName.value + ' ' + lastName.value },
set(v) { [firstName.value, lastName.value] = v.split(' ') }
})
- getter 走同樣的緩存邏輯。
- setter 只是普通函數(shù),無(wú)緩存要求,因此可以包含異步(但仍不推薦,因?yàn)?setter 觸發(fā)后 getter 需同步返回新值)。
總結(jié)
computed 用「dirty 位 + 惰性 effect」實(shí)現(xiàn)同步緩存,用「拒絕異步」換取數(shù)據(jù)一致性。理解了這一點(diǎn),你就掌握了 Vue 性能調(diào)優(yōu)的第一把鑰匙。
到此這篇關(guān)于深入理解Vue3 computed的文章就介紹到這了,更多相關(guān)Vue3 computed內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue初始化頁(yè)面閃動(dòng)(FOUC)問(wèn)題的終極解決方案
你是否遇到過(guò)頁(yè)面加載瞬間,用戶(hù)看到滿(mǎn)屏的 {{ message }}、{{ user.name }} 等未編譯的模板標(biāo)簽,幾毫秒后才恢復(fù)正常,這就是 Vue 初始化閃動(dòng)問(wèn)題,也稱(chēng)為 FOUC,本文將提供完整、可靠、可落地的解決方案,徹底根除此問(wèn)題,需要的朋友可以參考下2025-10-10
Vue 使用typescript如何優(yōu)雅的調(diào)用swagger API
這篇文章主要介紹了Vue 使用typescript如何優(yōu)雅的調(diào)用swagger API,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
Vue實(shí)現(xiàn)一種簡(jiǎn)單的無(wú)限循環(huán)滾動(dòng)動(dòng)畫(huà)的示例
這篇文章主要介紹了Vue實(shí)現(xiàn)一種簡(jiǎn)單的無(wú)限循環(huán)滾動(dòng)動(dòng)畫(huà)的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
vue實(shí)現(xiàn)購(gòu)物車(chē)拋物線(xiàn)小球動(dòng)畫(huà)效果的方法詳解
這篇文章主要介紹了vue實(shí)現(xiàn)購(gòu)物車(chē)拋物線(xiàn)小球動(dòng)畫(huà)效果的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了vue.js實(shí)現(xiàn)拋物線(xiàn)動(dòng)畫(huà)效果購(gòu)物車(chē)功能相關(guān)原理與操作注意事項(xiàng),需要的朋友可以參考下2019-02-02
Vue3中reactive函數(shù)toRef函數(shù)ref函數(shù)簡(jiǎn)介
這篇文章主要介紹了Vue3中的三種函數(shù),分別對(duì)reactive函數(shù)toRef函數(shù)以及ref函數(shù)原理及使用作了簡(jiǎn)單介紹,有需要的朋友可以借鑒參考下2021-09-09
vue虛擬滾動(dòng)/虛擬列表簡(jiǎn)單實(shí)現(xiàn)示例
本文主要介紹了vue虛擬滾動(dòng)/虛擬列表簡(jiǎn)單實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01
uni-app自定義導(dǎo)航欄按鈕|uniapp仿微信頂部導(dǎo)航條功能
這篇文章主要介紹了uni-app自定義導(dǎo)航欄按鈕|uniapp仿微信頂部導(dǎo)航條,需要的朋友可以參考下2019-11-11
Nuxt 嵌套路由nuxt-child組件用法(父子頁(yè)面組件的傳值)
這篇文章主要介紹了Nuxt 嵌套路由nuxt-child組件用法(父子頁(yè)面組件的傳值),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
基于Vue實(shí)現(xiàn)tab欄切換內(nèi)容不斷實(shí)時(shí)刷新數(shù)據(jù)功能
在項(xiàng)目開(kāi)發(fā)中遇到這樣需求,就是有幾個(gè)tab欄,每個(gè)tab欄對(duì)應(yīng)的ajax請(qǐng)求不一樣,內(nèi)容區(qū)域一樣,內(nèi)容為實(shí)時(shí)刷新數(shù)據(jù),實(shí)現(xiàn)方法其實(shí)很簡(jiǎn)單的,下面小編給大家?guī)?lái)了基于Vue實(shí)現(xiàn)tab欄切換內(nèi)容不斷實(shí)時(shí)刷新數(shù)據(jù)功能,需要的朋友參考下吧2017-04-04

