前言

  • vue3诸多API中computed的作用毋庸置疑,也算是我们开发中使用比较多的API了。今天就让我们来探究下computed底层到底做了什么。如果想要学好computed个人觉得还是需要将effect有个深入的理解。这样学的东西才能融会贯通。
  • 为什么一定强调学习effect呢?因为无论是watchcomputed都是以effect为基础,所以说基石很重要,如果大家看源码实在很吃力的话,个人觉得看懂我写的就够了。因为我就是按照源码一比一写出来的
  • 讲述方式:
    • 基本使用
    • 手写源码
    • 源码对照

基本使用

为了防止一部分人对computed不是很熟悉,这里也会简单说下使用方式。其实这个使用方式也是结合之后的手写源码来说的。

      const data = { name: 'lihh', age: 20 }const state = reactive(data)const newAge = computed(() => state.age)effect(() => {document.getElementById('app').innerHTML = `我叫${state.name}, 我今年${newAge.value}岁了`})setTimeout(() => {state.age++}, 4000)
  • computed依赖reactive的值进行计算,而effect依赖computed的值进行计算
    - 上述这个实例就是两个effect相互嵌套的问题,其中包含着诸多响应式属性以及两个effect。这里给逐一分析下:

    • APIeffect本身就是一个effect
    • computed是一个effect
    • 变量newAge是通过reactiveage来计算出来的
    • 变量age收集computedEffect。而computed本身收集渲染effect。所以可谓是牵一发动全身

手写源码

APIcomputed是使用比较多的api了。在面试过程中问到的比较多,有个最经典的问题computed 跟 watch有什么不同。也请大家带着这个疑问来看这段代码

  • computed本身的实现
      const computed = (getterOrOptions) => {let getterlet setterif (isFunction(getterOrOptions)) {getter = getterOrOptions// 此处标识computed是只读的setter = Function.prototype} else {getter = getterOrOptions.getsetter = getterOrOptions.set}const res = new ComputedRefImpl(getter, setter)return res}
  • computed本身有两种使用方式:

    • const xxx = computed(() => state.age)
    • const xxx1 = computed({get: () => {}, set: () => {}})
  • 这里需要统一做下区分,同时调用实现类ComputedRefImpl
  • 这个方法比较简单,接下来我们重点分析下类ComputedRefImpl
  • ComputedRefImpl实现
      class ComputedRefImpl {constructor(getter, setter) {this.getter = getterthis.setter = setterthis._value = undefinedthis.deps = new Set()this._dirty = truethis.__v_isRef = truethis.effect = new ReactiveEffect(getter, () => {if (!this._dirty) {this._dirty = true// 触发依赖triggerEffect(this.deps)}})}get value() {// 进行依赖收集trackEffect(this.deps)if (this._dirty) {this._value = this.effect.run()this._dirty = false}return this._value}set value(newValue) {this.setter(newValue)}}
  • 上述就是关键类ComputedRefImpl实现方式了。这里会逐一进行讲解:

    • this._value 保存获取的值
    • this.deps 保存依赖的effect。这里的effect就是渲染effect
    • this._dirty 用来进行缓存的
  • 整个执行流程:
    • 这里不得不提到一点,compuetd本身是惰性的,不像watch以及effect一样。默认就会执行一次。只有调用的时候才会执行
    • 还有通过上述代码我们会发现,在构造函数中我们使用了ReactiveEffect来创建一个effect。这个类我们赋值了一个getter函数以及scheduler函数
    • 分析下执行流程:
      • 步骤1:执行代码我今年${newAge.value}岁了的时候,因为牵扯到了newAge.value。会执行到类ComputedRefImplget value函数中去
      • 步骤2:此时激活的effect是渲染effect,从而对其进行收集,体现这种话trackEffect(this.deps)
      • 步骤3:判断变量this._dirty。开始执行if内的代码,获取到最新的值,同时将this._dirty设置为false。如果在值未修改的情况下再次获取值的时候,直接使用上次返回的值
      • 步骤4:如果值发生了变化会执行scheduler函数,重新将变量_dirty设置为true。如果下次再次获取值重新执行步骤3

源码对照

  • computed入口

地址:packages\reactivity\src\computed.ts,函数computed

export function computed<T>(getter: ComputedGetter<T>,debugOptions?: DebuggerOptions
): ComputedRef<T>
export function computed<T>(options: WritableComputedOptions<T>,debugOptions?: DebuggerOptions
): WritableComputedRef<T>
export function computed<T>(getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,debugOptions?: DebuggerOptions,isSSR = false
) {// 预制的getter setterlet getter: ComputedGetter<T>let setter: ComputedSetter<T>// 判断是否是函数const onlyGetter = isFunction(getterOrOptions)if (onlyGetter) {getter = getterOrOptionssetter = __DEV__? () => {console.warn('Write operation failed: computed value is readonly')}: NOOP} else {getter = getterOrOptions.getsetter = getterOrOptions.set}const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)return cRef as any
}
  • ComputedRefImpl实现

地址:packages\reactivity\src\computed.ts。类:ComputedRefImpl
这里代码就不粘贴了。太长了没意义。而且写法跟我手写几乎保持一致。所以看我的就够了

结束

如果我的分析对大家有帮助的话,希望大家点赞~~收藏~关注一条龙服务啊
源码地址:https://gitee.com/li_haohao_1/vue-world/tree/master/vue3/computed

vue3源码系列之计算属性computed原理剖析相关推荐

  1. Vue3源码阅读指南——计算属性(effectcomputed)

    在阅读Vue3响应式数据部分的源代码时,effect和computed部分的确有着其设计精巧之处.其代码实现是在packages/reactivity/effect.ts和packages/react ...

  2. vue 计算属性_lt;Vue 源码笔记系列6gt;计算属性 computed 的实现

    1. 前言 原文发布在语雀: <Vue 源码笔记系列6>计算属性 computed 的实现 · 语雀​www.yuque.com 上一章我们已经学习过 watch,这一章就来看一下计算属性 ...

  3. vue源码-对于「计算属性」的理解

    vue源码-对于「计算属性」的理解 这是我最近学习vue源码的一个个人总结和理解,所以可能并不适合每一位读者 本文的整体脉络如下,首先尽可能去掉细节,对计算属性源码的大致实现有一个了解,然后举一例子, ...

  4. java源码系列:HashMap底层存储原理详解——4、技术本质-原理过程-算法-取模具体解决什么问题

    目录 简介 取模具体解决什么问题? 通过数组特性,推导ascii码计算出来的下标值,创建数组非常占用空间 取模,可保证下标,在HashMap默认创建下标之内 简介 上一篇文章,我们讲到 哈希算法.哈希 ...

  5. c++ map 获取key列表_好未来Golang源码系列一:Map实现原理分析

    分享老师:学而思网校 郭雨田 一.map的结构与设计原理 golang中map是一个kv对集合.底层使用hash table,用链表来解决冲突 ,出现冲突时,不是每一个key都申请一个结构通过链表串起 ...

  6. java源码系列:HashMap底层存储原理详解——5、技术本质-原理过程-算法-取模会带来一个什么问题?什么是哈希冲突?为什么要用链表?

    目录 取模会带来一个什么问题? 演示什么是哈希冲突(哈希碰撞)? 为什么要用链表? 其他--布隆过滤器 取模会带来一个什么问题? 好,那同学们这样他能达到一个目的,但是呢,它也会带来的一个问题,那它会 ...

  7. Spring源码系列(十二)Spring创建Bean的过程(二)

    1.写在前面 上篇博客主要Spring在创建Bean的时候,第一次调用的Bean的后置处理器的过程,同时笔者也打算将整个Spring创建的Bean的过程,通过这个系列,将Bean的创建过程给讲清楚,废 ...

  8. Vue 3.0 源码计算属性 Computed的实现

    我们来看下 计算属性源码是怎么实现的呢? 参数 getterOrOptions 是判断是写的 第一种是 函数只有getter computed(()=>{ }); 第二种 是 对象 有get 跟 ...

  9. Vue3计算属性computed

    计算属性computed是用来存储属性数据的 对数据进行逻辑处理操作,实现数据包装 计算属性通常依赖于当前vue对象中的普通属性 当依赖的依赖的普通属性发生变化的时候,计算属性也会发生变化 计算属性俩 ...

最新文章

  1. 戏说肥哥系列之---买车
  2. Spring Boot由jar包转成war包
  3. python读取文件的常用方法
  4. 深入理解事件循环机制
  5. 2.5 矩阵乘法规则
  6. 防火墙配置十大任务之十,构建虚拟防火墙
  7. Spark之hive的UDF自定义函数
  8. MyBatis学习总结(7)——Mybatis缓存
  9. 三.redis 排序
  10. C# DateTime类
  11. win10开启多用户同时远程登录-很详细
  12. 【图像加密】基于matlab RSA图像加密解密【含Matlab源码 1442期】
  13. lm358 pdf应用电路资料及引脚图
  14. mtk充电电流文件_MT2503 系列充电电流问题
  15. C语言实现单链表首尾相连
  16. DAS、NAS、SAN三种高端存储技术分析
  17. LSI阵列卡的使用教程
  18. 网络加密流量的相关研究
  19. 第1节 细胞是生命活动的基本单位
  20. $timeout、$interval和$watch用法

热门文章

  1. deform服务器位置,Deform V11 自动多工步分析(MO)设置详解-工艺成型及仿真
  2. 用golang处理pdf: 截取pdf和合并pdf
  3. AltiumDesigner如何绘制PCB封装
  4. Cast方法oracle,oracle 中cast方法的使用
  5. exec函数族的基本用法
  6. 作为一个程序员,你是怎么管理文档资料的?我这个方法特别方便
  7. java客户端发消息到kafka
  8. 人脸检测和识别的开源库总结
  9. 低功耗蓝牙开发入门概念科普
  10. 信息学奥赛一本通1258:【例9.2】数字金字塔题解