深入理解Vue3 computed

 更新时间:2025年08月27日 09:21:05   作者:前端小巷子  
本文主要介绍了Vue3 computed的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在模板里写一行 {{ sum }},背后却藏着「惰性求值 + 精准依赖收集 + 脏检查缓存」的三重魔法。本文带你钻进源码,拆解 computed 如何决定「何时算、何时不、为何不能异步」。

一、使用方法

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

看似普通,但注意两点:

  • 只读:sum 不是函数,而是一个「带缓存的 getter」。
  • 懒执行:直到第一次读取 value,计算函数才真正跑一遍。

二、缓存机制:dirty 标志位

源码核心只有两行状态机:

let value: any
let dirty = true
  • dirty 为 true → 需要重新计算
  • dirty 为 false → 直接返回旧值

首次读取 sum.value 时,dirty 从 true 变为 false,并把结果存入 value

当依赖的响应式数据变化,调度器把 dirty 重新置为 true,但不会立即计算,而是等待下一次读取。

这就是「缓存」的本质:用 1 bit 的布尔值换一次昂贵的计算。

三、依赖收集:effect 包裹 getter

computed 的计算函数被 effect 包装成副作用:

const effectFn = effect(getter, {
  lazy: true,
  scheduler() {
    dirty = true
    trigger(obj, TriggerOpTypes.SET, 'value')
  }
})
  • lazy: true 阻止首次执行,实现惰性求值。
  • scheduler 在依赖变化时只打标记,不立即重算,确保缓存语义。

当模板读取 sum.valuetrack 把当前渲染副作用注册到 computed 的依赖图;当 state.a 变化,trigger 通知渲染器重新执行,渲染器再去读 sum.value,此时才真正触发计算。

四、为什么拒绝异步?

设想一个异步 computed:

const asyncSum = computed(async () => {
  const res = await fetch('/api/sum?a=' + state.a)
  return res.json()
})

问题立刻暴露:

  1. 缓存无法兑现

    第一次读取返回一个 Promise,第二次读取依赖并未变化,但缓存里存的是 Promise,无法直接返回结果。

  2. 渲染时数据缺位

    模板在渲染阶段需要同步值,异步导致视图出现空档或闪烁。

  3. 依赖追踪混乱

    异步完成时间不确定,期间若依赖再次变化,无法确定哪一次结果是最新。

Vue 官方给出的替代方案是 watch + ref

const asyncSum = ref(0)
watch(state, async () => {
  asyncSum.value = await fetch('/api/sum?a=' + state.a).then(r => r.json())
})

watch 不缓存、不阻塞渲染,天然适合异步副作用。

五、可写 computed:缓存 + setter 的双通道

const fullName = computed({
  get()   { return firstName.value + ' ' + lastName.value },
  set(v)  { [firstName.value, lastName.value] = v.split(' ') }
})
  • getter 走同样的缓存逻辑。
  • setter 只是普通函数,无缓存要求,因此可以包含异步(但仍不推荐,因为 setter 触发后 getter 需同步返回新值)。

总结

computed 用「dirty 位 + 惰性 effect」实现同步缓存,用「拒绝异步」换取数据一致性。理解了这一点,你就掌握了 Vue 性能调优的第一把钥匙。

到此这篇关于深入理解Vue3 computed的文章就介绍到这了,更多相关Vue3 computed内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue初始化页面闪动(FOUC)问题的终极解决方案

    Vue初始化页面闪动(FOUC)问题的终极解决方案

    你是否遇到过页面加载瞬间,用户看到满屏的 {{ message }}、{{ user.name }} 等未编译的模板标签,几毫秒后才恢复正常,这就是 Vue 初始化闪动问题,也称为 FOUC,本文将提供完整、可靠、可落地的解决方案,彻底根除此问题,需要的朋友可以参考下
    2025-10-10
  • Vue 使用typescript如何优雅的调用swagger API

    Vue 使用typescript如何优雅的调用swagger API

    这篇文章主要介绍了Vue 使用typescript如何优雅的调用swagger API,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Vue实现一种简单的无限循环滚动动画的示例

    Vue实现一种简单的无限循环滚动动画的示例

    这篇文章主要介绍了Vue实现一种简单的无限循环滚动动画的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • vue实现购物车抛物线小球动画效果的方法详解

    vue实现购物车抛物线小球动画效果的方法详解

    这篇文章主要介绍了vue实现购物车抛物线小球动画效果的方法,结合实例形式较为详细的分析了vue.js实现抛物线动画效果购物车功能相关原理与操作注意事项,需要的朋友可以参考下
    2019-02-02
  • Vue3中reactive函数toRef函数ref函数简介

    Vue3中reactive函数toRef函数ref函数简介

    这篇文章主要介绍了Vue3中的三种函数,分别对reactive函数toRef函数以及ref函数原理及使用作了简单介绍,有需要的朋友可以借鉴参考下
    2021-09-09
  • vue虚拟滚动/虚拟列表简单实现示例

    vue虚拟滚动/虚拟列表简单实现示例

    本文主要介绍了vue虚拟滚动/虚拟列表简单实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-01-01
  • uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能

    uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能

    这篇文章主要介绍了uni-app自定义导航栏按钮|uniapp仿微信顶部导航条,需要的朋友可以参考下
    2019-11-11
  • Nuxt 嵌套路由nuxt-child组件用法(父子页面组件的传值)

    Nuxt 嵌套路由nuxt-child组件用法(父子页面组件的传值)

    这篇文章主要介绍了Nuxt 嵌套路由nuxt-child组件用法(父子页面组件的传值),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • 基于Vue实现tab栏切换内容不断实时刷新数据功能

    基于Vue实现tab栏切换内容不断实时刷新数据功能

    在项目开发中遇到这样需求,就是有几个tab栏,每个tab栏对应的ajax请求不一样,内容区域一样,内容为实时刷新数据,实现方法其实很简单的,下面小编给大家带来了基于Vue实现tab栏切换内容不断实时刷新数据功能,需要的朋友参考下吧
    2017-04-04
  • vue上传图片文件的多种实现方法

    vue上传图片文件的多种实现方法

    这篇文章主要给大家介绍了关于vue上传图片文件的相关资料,介绍了利用原始input标签form表单上传、elementui自带的el-upload上传以及elementui实现一次性上传多张图片等方法,需要的朋友可以参考下
    2021-05-05

最新评论