深入Vue3响应式核心:computed 的实现原理与应用

Vue3响应式系统的底层原理与实践要点你真的懂吗? 我们可以用生活中的恒温热水器类比Vue的响应式系统:当水温低于设定值时,热水器会自动加热;当水温过高时,会停止加热——状态变化触发自动反馈。当JavaScript状态(如变量、对象属性)发生变化时,Vue会自动更新依赖该状态的UI或逻辑。“Vue 的响应式系统会跟踪 JavaScript 状态并在其发生变化时触发更新。比如你有一个计数器变量count,当count从0变成1时,页面上显示count的地方会自动更新为1,无需手动操作DOM。 阅读详情

在 Vue3 中,computed是一个看似简单却比较精妙的 API。最主要是能自动缓存计算结果,并在依赖变化时重新触发更新。因此,computed 是如何知道自己的依赖变了,并执行对应的响应式更新函数进行执行的呢?
本文将带你深入 computed 的内部实现和相关核心机制,通过简化的源码分析 “依赖收集 → 脏标记 → 触发更新” 的完整链路。

一、computed 的基本用法

<script setup>
import { reactive, computed } from 'vue'

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

// 一个计算属性 ref,第一种写法:函数式传参computed(fn)
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
// 第二种写法:
const publishedBooksMessage = computed({
	get() {
	return author.books.length > 0 ? 'Yes' : 'No'
	},
	set(newVal) {
		author.books = newVal // 更新author.books数据
	}
})
</script>

<template>
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</template>

自动缓存:只要 author.books 不变,多次访问 publishedBooksMessage 不会重复计算
响应式:当 author.books 变化,publishedBooksMessage 的值自动更新
这些特性背后,是一套精细的响应式协作机制。

二、简化版 computed 源码

import { track, trigger } from "./reactive";
import { effect } from "./effect";
import { ref } from "vue";
class computedRefImpl {
    
    constructor(getter, setter) {
        this._value = undefined;
        this._dirty = true; // 进行惰性求值的关键标志
        this.setter = setter;
        this.effect = effect(getter, { // this.effect 执行时在 getter 中依赖的响应式数据会track对应内部设置的Effect实例
            lazy: true, // 默认懒执行
            scheduler: () => { // 依赖的数据更新时会触发执行
                if(!this._dirty) {
                    this._dirty = true;
                    trigger(this, 'value', 'set'); // 触发computed依赖的activeEffect执行
                }
            }
        })
    }
    get value() {
        if(this._dirty) { // '脏值'重新执行getter获取新值
            this._value = this.effect();
            this._dirty = false; // 设置缓存,后续依赖的数据未更新时直接返回原有获取的值
        }
        track(this, 'value'); // track 收集computed依赖的activeEffect
        return this._value;
    }
    set value(newValue) {
        this.setter && this.setter(newValue); // 该函数设置更新响应式依赖的数据后执行scheduler对应computed依赖的activeEffect
    }
}

function computed(getterOrOptions) {
    let getter;

    let setter;

    if(typeof getterOrOptions === 'function'){ // getterOrOptions 为函数时
        getter = getterOrOptions;
    }else{ // 配置对象方式
        getter = getterOrOptions?.get;
        setter = getterOrOptions?.set || (() => {});
    }
    return new computedRefImpl(getter, setter);
}

// 示例1
const a = ref(1);
const b = computed(() => a.value + 1);

effect(() => {

    console.log(b.value); // 输出2

})

setTimeout(() => {
    a.value = 2; // 输出3
}, 1000);



// 示例2
const d = ref(1);
const c = computed({
    get: () => d.value + 1,
    set: (newValue) => {
        d.value = newValue;
    }
})
effect(() => {
    console.log(c.value); // 2  2s后为4
})
setTimeout(() => {
    c.value = 3;
}, 2000);


三、依赖是如何被收集的?

1.示例1中的computed 怎么知道它依赖了 a 数据

在首次读取 .value 时,通过activeEffect 机制自动收集,并在constructor中对依赖的数据收集内部自己的activeEffect ,将来在依赖的数据更新时则会触发scheduler执行从而触发原来 .value 时收集到的activeEffect。

步骤分解:

1.创建 computed 时(lazy: true)
getter 不会立即执行
此时 a 完全不知道 computed 的存在

2.首次访问 b.value
进入 get value() ,因 _dirty = true,执行 this.effect()
this.effect() 即运行对应的getter:() => a.value + 1
收集track computed自己的effect

3.执行 getter 时的关键过程:
activeEffect = this.effect; // 设置当前激活的 effect
const result = getter(); // 访问 a.value
track 内部将 activeEffect(即 computed.effect)加入 a 的依赖列表

结果:a 现在知道变化时通知对应的computed,这就是 “懒依赖收集”,只在真正使用时建立依赖,避免无用开销。

四、依赖变化后,如何触发更新?

问题:a.value = 2 后,computed 是怎么知道要重新计算的

答案:通过 scheduler 提前标记 _dirty = true,并执行trigger触发computed已track的effect。

五、为什么需要 _dirty 和惰性求值

假设没有 _dirty 缓存:

// 每次访问都重新计算
get value() {
  return this.effect(); // 每次都执行 getter
}

后果:性能浪费:即使依赖未变,也重复计算
副作用风险:如果 getter 有副作用比如复杂计算会多次执行

而缓存的设计:
只在依赖变化后标记 _dirty = true,只在下次读取时才重新计算
,无人读取则永不计算

这就是 “惰性求值”

六、计算属性缓存 vs 方法

在文章开头所使用的示例,你可能注意到我们在表达式中像这样调用一个函数也会获得和计算属性相同的结果:

template
<p>{{ calculateBooksMessage() }}</p>
js
// script
function calculateBooksMessage() {
  return author.books.length > 0 ? 'Yes' : 'No'
}

若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books 不改变,无论多少次访问 publishedBooksMessage 都会立即返回先前的计算结果,而不用重复执行 getter 函数。为什么需要缓存呢?想象一下我们有一个非常耗性能的计算属性 list,需要循环一个巨大的数组并做许多计算逻辑,并且可能也有其他计算属性依赖于 list。没有缓存的话,我们会重复执行非常多次 list 的 getter,然而这实际上没有必要!如果你确定不需要缓存,那么也可以使用方法调用。

七、结语

computed 的实现体现了 Vue 3 响应式系统的三大核心思想:
1.精准依赖追踪:通过 activeEffect + track/trigger 自动追踪依赖
2.惰性与缓存:只在必要时计算,避免无效工作
3.分层解耦:依赖数据作为中间层,向下监听、向上通知,职责清晰
因此,computed不仅是一个简单的api函数,更是响应式编程思想的完美体现。如果有问题也欢迎大家一起在评论区交流沟通!

Vue3响应式核心:ref、reactive、computed与v-show的底层契约 Vue3响应式系统基于Proxy构建,其本质是围绕‘响应式所有权’与‘依赖追踪活性’建立的一套运行契约。ref封装独立响应式单元,支持解构与跨作用域传递;reactive提供深度代理对象,但解构即失活;computed并非缓存getter,而是数据流阀门,依赖源头变更驱动更新;v-show的显隐切换实为watchEffect的语法糖,仅对活跃响应式引用生效。理解这些基础原理,才能规避组合式API中90%的隐性失效问题,如props解构后v-show不更新、computed赋值报错、toRefs误用导致响应性 阅读详情

相关推荐

【UE5 C++开发指南】从零配置Visual Studio 2022开发环境

本文详细指导如何从零开始为UE5 C++开发配置Visual Studio 2022环境。文章强调了VS2022与UE5的深度兼容性,并逐步讲解了社区版下载、核心工作负载(如“使用C++的游戏开发”)与组件安装、界面优化、专属工具设置以及首个C++项目的创建与验证流程,帮助开发者高效搭建专业开发环境。

weixin_29016865的博客 394

Vue3核心语法回顾与Composition深入

Vue3核心语法与Composition API深入解析 本文介绍了Vue3的核心语法和Composition API使用要点,包含以下主要内容: 项目环境配置与创建 使用nvm管理Node版本 创建Vue3+TypeScript项目的基本流程 响应式计数器实现 使用ref创建响应式变量 模板自动解包特性 TypeScript类型标注实践 ref与reactive对比 ref包装对象的最佳实践 reactive直接解构的风险 响应式数据管理方案选择指南 TypeScript集成技巧 类型断言处理DOM事件

weixin_52185313的博客 617

人工智能-CS188 Project 2: Multi-agents

一、项目介绍 项目介绍网页 项目代码下载 本项目是采用Berkeley的CS188课程内容实习二的内容,在这个项目中,我们将为经典版本的Pacman 设计自动算法,包括幽灵。在此过程中,我们将实现 minimax 和 expectimax 搜索并尝试评估函数设计 完成作业只需要完成5个题目,按照项目介绍的步骤进行完成,主要是在multiAgents.py文件中进行补充代码 二、代码详情 1、Question1:Reflex Agent 略 2、Question2:Minimax 套用ppt上的minm

xiten的博客 8285

Vue3(篇一) 核心概念——响应式模板语法与组件基础

如何高效地构建用户界面?传统的做法是用原生 JS 操作 DOM——获取元素、绑定事件、更新内容。这种方式在小项目中尚可,但一旦项目变大,代码就会变得难以维护。你需要在数据变化时手动更新页面,在用户操作时手动同步数据,繁琐且容易出错。Vue3 正是为了解决这个问题而生——它提供了一套"响应式"机制,让数据和页面自动同步。你只需要关注数据本身,页面会自动更新。响应式数据与数据绑定。概念作用关键点响应式数据数据变化自动更新视图ref适用于任意类型,reactive适用于对象数据绑定数据与视图同步。

勇往直前的博客 411

深入分析大众点评 Ajax 接口:直接请求 JSON 数据高效获取评论

大众点评网站采用前后端分离架构,通过Ajax接口动态加载数据。按F12打开开发者工具,切换到Network(网络)面板。实际环境中,我们需要使用Python重现这一加密逻辑。查看请求响应,寻找包含评论数据的JSON接口。参数是大众点评的反爬机制核心,需要特别处理。:尊重网站的robots.txt文件规定。:仅将数据用于合法合规的研究和分析目的。:不侵犯大众点评的商业秘密和知识产权。打开大众点评网站,进入任意商户页面。:对采集到的用户信息进行脱敏处理。:避免对目标网站造成过大负担。

Z_suger7的博客 1583

RH850从0搭建Autosar开发环境【3X】- Davinci Configurator之BswM模块配置详解(上)

RH850从0搭建Autosar开发环境【3X】- Davinci Configurator之BswM模块配置详解(上)

weixin_42412049的博客 740

Proxy与Reflect详解(三):面试实战篇——高频面试题深度剖析

本篇文章主要讲解了 Proxy与Reflect详解(三):面试实战篇——高频面试题深度剖析 从进阶到面试的实战讲解

x15514104477的博客 359

SAP 错误消息调试之七种武器:让所有的错误消息都能被定位

目录 长生剑 - SAPGUI Where Used List 碧玉刀 - ABAP调试器观察点 霸王枪 - ABAP调试器动态断点 多情环 - ABAP代码静态扫描 孔雀翎 - SAT 离别钩 - ST05 拳头 - 迷之方法??? Jerry在2018年开始用中文在微信公众号平台上写作之前,在SAP官方社区上总共写了639篇英文博客。 其中有一篇写于2013年介绍ABAP调试技巧的博客:

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2810

深入解析 Vue 3 响应式原理与优化技巧

Vue 3 的响应式系统基于Proxy实现,这使得 Vue 3 在响应式设计上比 Vue 2 有了更大的性能提升和灵活性。Vue 2 使用了来代理数据访问和修改,而 Vue 3 使用了现代浏览器的ProxyAPI 来实现更加高效的响应式机制。Vue 3 响应式系统的核心思想是将对象的属性变为 getter 和 setter,数据变化时通过依赖收集和触发更新来重新渲染视图。通过代理对象的属性访问,Vue 3 能够动态地追踪数据变化,并使视图实时更新。

一名热衷于技术的全栈开发者,专注于前端与后端的全面技术探索。在这里,我将分享我在技术领域的学习与成长,助力更多开发者的进步。 3169

基于Simulink进行多相电机EMI抑制的仿真建模

特点高可靠性:通过增加相数来提供冗余,增强系统的故障容忍度。低转矩脉动:改善了电机的动态性能,减少了转矩波动。复杂的EMI管理:更多的相数意味着更复杂的电磁环境,增加了EMI抑制的难度。挑战模型复杂性:涉及电气、机械和电磁场等多个领域的相互作用。实时性要求:控制系统需要能够快速响应以适应动态负载变化。多变量优化:包括滤波器设计、PWM调制策略等在内的多个参数需综合考虑以找到最优解。使用Simscape Electrical库来构建一个多相电机模型。

amy_mhd的博客 273

国科大作业考试资料《人工智能原理与算法》2024新编-第二次作业整理

1、对于下列活动,分别给出任务环境的PEAS描述, 并按2.3.2节列出的性质进行分析: 3、为图2.2中描述的吸尘器世界实现一个可以进行性能度量的环境模拟器。你的实现是必须是模块化的,以使传感器、执行器和环境特征(大小、形状、灰尘放置等)便于修改。 4、实现上述题目真空吸尘器环境中的简单反射Agent。用所有可能的初始灰尘分布和Agent位置,运行环境模拟器和Agent。记录Agent在每种情况下的性能评分和总体平均评分。

MatsumotoChrikk 1187

Vue3 响应式原理与响应式属性 详解

点我+1

萌新程序员的博客,觉得有用的可以点点关注 1179

NVIDIA Omniverse 技术浅析(二):USD

例如,一个用户可以负责场景的几何体设计,另一个用户可以负责材质和灯光的调整。USD 的开放性和可扩展性,结合 Omniverse 的 Kit 扩展框架,使得用户和开发者可以创建自定义的应用程序和工具,以满足特定的需求。USD 的材质和物理属性系统,结合 Omniverse 的 RTX 实时渲染技术,使得用户可以在虚拟环境中看到逼真的光影效果和物理模拟。USD 的时间轴和动画功能,结合 Omniverse 的物理属性系统,使得用户可以为虚拟环境中的元素创建复杂的动画和物理模拟。

m0_75253143的博客 445

Vue的computed和watch的原理?

Vue中的computed和watch均基于响应式系统实现,但机制和用途不同。computed是带缓存的派生值计算器,依赖不变时复用结果,适合数据格式化等场景;watch是数据监听器,响应变化执行副作用,适合异步操作等逻辑。computed需返回计算值且避免副作用,watch需精简监听源并慎用深度监听。二者在缓存特性、返回值和使用场景上存在明显差异,正确选择可提升代码效率和可维护性。

1842

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

深入解析 Vue3 响应式系统:原理、性能优化与应用场景

Vue3 中的响应式系统是基于现代 JavaScript 的Proxy和Reflect实现的。为了理解 Vue3 响应式系统的工作原理,我们需要先了解这两个对象。依赖收集(Dependency Collection)是 Vue3 响应式系统的核心功能之一。在响应式系统中,当我们访问某个响应式对象的属性时,Vue3 会自动追踪该属性依赖的函数或组件。这些被追踪的函数或组件会在数据发生变化时重新执行。这种机制保证了只有在数据发生变化时,相关组件才会重新渲染,从而避免了不必要的性能消耗。

程序员林北北的博客 1449

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Vue 3响应式原理及实现

1. 实现响应式 响应基本类型变量 首先看一下响应式预期应该是什么样的,新建一个 demo.js 文件,内容如下: //这种写成一行完全是为了节省空间,实际上我会一行一个变量 leta=1,b=2,c=a*b console.log('c:'+c)//2 a=2 console.log('c:'+c)//期望得到4 思考一下,如何才能做到当 a 变动时 c 跟着变化? 显然,我们需要做的就是重新执行一下 let c = ...

skydust1979的博客 1983

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Vue的computed与watch底层实现原理

Vue的computed与watch实现原理摘要 计算属性(computed):通过惰性求值和缓存机制优化性能。Vue为每个计算属性创建专门的Watcher,标记为lazy模式。只有当依赖数据变化时(dirty标记为true)才会重新计算,否则直接返回缓存值。底层通过依赖收集系统建立响应式关联,计算属性Watcher会收集模板Watcher作为依赖。 侦听器(watch):基于用户自定义Watcher实现,支持深度监听(deep)、立即执行(immediate)等特性。当监听数据变化时,会触发回调函数执行,

LYFlied的博客 1079

理解Vue 3响应式系统原理

Vue 3的诞生背景:Vue 2的局限与改进需求Vue 3的主要版本发布日期和目标:稳定性和性能的提升响应式系统:是一种数据绑定机制,在数据模型变化时,自动更新视图。在Vue中,响应式系统基于数据劫持和发布-订阅模式实现。

https://blog.cmdragon.cn/ 1715

Vue 3 Watch vs Computed 深度解析:从底层原理到最佳实践,彻底搞懂响应式核心

本文介绍了Vue 3中的computed计算属性,将其比作"数据加工厂",能够根据响应式数据自动派生新值并智能缓存。主要特点包括:1) 依赖追踪机制,仅当依赖数据变化时重新计算;2) 高效的缓存特性,避免重复计算;3) 声明式编程模式,简化复杂逻辑处理。文章通过购物车总价计算的实例,对比了传统写法与计算属性的优势,并深入剖析了其底层依赖追踪和缓存机制的工作原理。最后展示了只读计算属性的基本用法,说明如何通过getter函数创建响应式派生数据。

深耕 Vue 生态与 JS/TS 技术,聚焦组件封装、响应式原理、TS 类型设计,解析工程化配置与性能优化方案。同时分享 YOLOv8 目标检测实战、AI 大模型面试核心考点,以代码实例拆解技术实现与业务解法。 1013

前端面试专栏-主流框架:12. Vue3响应式原理与API

Vue3的响应式系统基于Proxy对象实现,相比Vue2有了显著的改进和提升。它通过高效的依赖收集和触发更新机制,实现了响应式数据到UI的自动更新。Vue3提供了丰富的响应式API,如reactive()、ref()、computed()、watch()等,这些API使得开发者能够更加灵活和高效地管理应用的状态。同时,Vue3的响应式系统在性能、功能和TypeScript支持方面都有明显的优势,为开发者提供了更好的开发体验。理解和掌握Vue3的响应式原理与API,对于开发高质量的Vue3应用至关重要。📌。

爱分享的程序员 865

Vue3响应式原理深度解析:别再只会用ref和reactive了

Vue3的响应式系统不是黑魔法,是有原理的。别再只会用ref和reactive了——理解原理,你的代码会更高效、更可控。响应式系统就像汽车的发动机,你不需要成为机械师,但了解基本原理能让你更好地驾驶。别只会踩油门,也要知道什么时候该刹车。

大山哥 4991

vue3 中的响应式设计原理

本文带大家从头开始学习如何实现简单版 Vue 3 响应式,实现了 Vue3 Reactivity 中的核心方法(effect/track/trigger/computed/ref等方法),提高项目开发效率和代码调试能力。

zz130428的博客 746

Vue3 响应式原理拆解:从 Proxy 陷阱到组合式架构的性能边界

Vue3 的响应式系统基于 Proxy 实现了自动依赖收集,大幅降低了状态管理的代码量。但自动不等于免费,理解底层机制才能写出高性能的代码。精准声明依赖:computed 中只访问需要的属性,避免整对象访问导致依赖膨胀。按需使用浅代理:对不需要深度追踪的大型数据结构使用shallowRef,减少 Proxy 创建和依赖追踪开销。组合式函数封装依赖:用 Composable 将响应式依赖隔离在函数内部,只暴露必要的接口,防止依赖泄漏。量化决策。

大山哥 5840

Vue3 中 computed 与 watch 的深度解析:从基础到进阶的全面对比

特性computedwatch目的计算并缓存值监听变化并执行副作用依赖声明隐式(自动追踪)显式(需指定监听源)缓存有(依赖不变时复用)无副作用不允许(应保持纯净)允许(核心职责)返回值必须返回值(作为响应式数据)无返回值(执行回调)深层监听自动支持 reactive 对象的属性变化需要deep选项(开销较大)初始执行按需执行(首次访问时)可选immediate选项控制computed和watch是 Vue3 响应式系统的两大支柱,各自在不同的场景中发挥着关键作用。

2401_85392853的博客 1834

Vue 3 响应式原理深度解析

Vue3 CompositionAPI 解决了Vue2 OptionsAPI在逻辑复用、代码组织和类型支持上的痛点。核心特性包括: 通过setup函数作为入口,支持响应式数据(ref/reactive)、计算属性(computed)和监听(watch/watchEffect) 提供独立的生命周期钩子函数(onMounted等) 支持跨组件通信(provide/inject)和路由状态管理(useRoute/useRouter) 可通过自定义组合式函数(useXxx)实现逻辑复用 天然支持TypeScript

ovo44的博客 1039
上一篇: Vue3响应式原理之ref篇
下一篇: vue3运行时核心模块之runtime-dom
Zhencode
博客等级 码龄7年 106粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值