vue3源码(三)computed

news2024/11/17 13:27:42

1.功能

接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。
默认不执行,在取值时执行,具有缓存功能,数据不变多次取值只触发一次取值计算。

import {
        reactive,
        effect,
        computed,
      } from "/node_modules/@vue/reactivity/dist/reactivity.esm-browser.js";
      const state = reactive({ name: "orange" });
      let aliasName = computed(() => {
        console.log("执行计算方法");
        return "_" + state.name;
      });
      console.log("开始取值111");
      console.log(aliasName.value);
      console.log(aliasName.value);
      console.log(aliasName.value);
      state.name = "apple";
      console.log(aliasName.value);

在这里插入图片描述

2.原理:脏值检测机制**

内部保存一个变量dirty,用来判断是否需要重新执行。默认值为true,需要执行,计算取值后,缓存结果,dirty改为false,后续取值判断为false,直接取缓存的值,依赖的属性发生变化后,dirty改为true

3.实现

console.log(aliasName)
在这里插入图片描述

import { isFunction } from "@vue/shared";
import { ReactiveEffect } from "./effect";
const noop = () => {};

class ComputedRefImpl {
  dep = undefined;
  effect = undefined;
  __v_isRef = true; // 代表是ref,需要用.value 取值
  _dirty = true;
  _value;
  constructor(getter, public setter) {
    // 此处不能使用effect 会立即执行,ReactiveEffect可以手动调用run方法执行
    this.effect = new ReactiveEffect(getter, () => {
      // 此方法为getter依赖的属性变化后执行的方法:scheduler
      this._dirty = true;
    });
  }

  get value() {
    if (this._dirty) {
      this._value = this.effect.run();
      this._dirty = false;
    }
    return this._value;
  }

  set value(value: any) {
    this.setter(value);
  }
}

export function computed(getterOrOptions) {
  let onlyGetter = isFunction(getterOrOptions);
  let getter;
  let setter;
  if (onlyGetter) {
    getter = getterOrOptions;
    setter = noop;
  } else {
    getter = getterOrOptions.get;
    setter = getterOrOptions.set;
  }
  return new ComputedRefImpl(getter, setter);
}

此时已经简单实现了computed,以下情况我们修改了state.name的值,理论上应该执行effect重新渲染页面,但是并未执行

const state = reactive({
        name: "orange",
      });
      let aliasName = computed(() => {
        console.log("执行计算方法");
        return "_" + state.name;
      });

      effect(() => {
        app.innerHTML = aliasName.value;
      });

      setTimeout(() => {
        state.name = "apple";
      }, 1000);

计算属性aliasName收集了state.nameeffect收集了计算属性aliasName,同时让计算属性收集effect,当计算属性依赖的属性变化后,不仅修改dirty值,同时触发effect

 get value() {
    // 证明是在effect中使用的
    if (activeEffect) {
      trackEffects(this.dep || (this.dep = new Set()));
    }
    if (this._dirty) {
      this._value = this.effect.run();
      this._dirty = false;
    }
    return this._value;
  }
this.effect = new ReactiveEffect(getter, () => {
      // 此方法为getter依赖的属性变化后执行的方法:scheduler
      this._dirty = true;
      triggerEffects(this.dep);
    });

调整effect.ts文件,抽出来方法trackEffectstriggerEffects

const targetMap = new WeakMap();
export function track(target, key) {
  // 如果取值操作没有发生在effect中,则不需要收集依赖
  if (!activeEffect) {
    return;
  }
  // 判断是否已经记录过
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  let dep = depsMap.get(key);
  if (!dep) {
    // 值为一个不重复数组
    depsMap.set(key, (dep = new Set()));
  }
  trackEffects(dep);
}

export function trackEffects(dep) {
  let shouldTrack = !dep.has(activeEffect);
  if (shouldTrack) {
    dep.add(activeEffect);
    activeEffect.deps.push(dep); //同时effect记住当前这个属性
  }
}

export function trigger(target, key, newValue, oldValue) {
  // 通过对象找到对应的属性 让这个属性对应的effect重新执行

  const depsMap = targetMap.get(target);
  if (!depsMap) {
    return;
  }
  const dep = depsMap.get(key); // name 或者 age对应的所有effect

  triggerEffects(dep);
}

export function triggerEffects(dep) {
  const effects = [...dep];
  // 运行的是数组 删除的是set
  effects &&
    effects.forEach((effect) => {
      // 正在执行的effect ,不要多次执行
      if (effect !== activeEffect) {
        if (!effect.scheduler) {
          effect.run();
        } else {
          effect.scheduler();
        }
      }
    });
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1419715.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自然语言推断:微调BERT

微调BERT 自然语言推断任务设计了一个基于注意力的结构。现在,我们通过微调BERT来重新审视这项任务。自然语言推断是一个序列级别的文本对分类问题,而微调BERT只需要一个额外的基于多层感知机的架构,如下图中所示。 本节将下载一个预训练好的…

Web前端开发工具总结

一、nvm,node,npm之间的区别 nodejs:在项目开发时的所需要的代码库。相当于JDK npm:nodejs 包管理工具,npm 可以管理 nodejs 的第三方插件。在安装的 nodejs 的时候,npm 也会跟着一起安装。相当于Maven。 …

Prompt Learning 的几个重点paper

Prefix Tuning: Prefix-Tuning: Optimizing Continuous Prompts for Generation 在输入token之前构造一段任务相关的virtual tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,PLM中的其他参数固定。针对自回归架构模型:在句子前面添…

uniapp瀑布流实现

1. 图片瀑布流&#xff1a; 不依赖任何插件&#xff0c;复制即可见效&#xff1a; <template><view class"page"><view class"left" ref"left"><image class"image" v-for"(item,i) in leftList" :k…

ASP.NET Core 过滤器 使用依赖项注入

过滤器是 ASP.NET Core 中的特殊组件&#xff0c;允许我们在请求管道的特定阶段控制请求的执行。这些过滤器在中间件执行后以及 MVC 中间件匹配路由并调用特定操作时发挥作用。 简而言之&#xff0c;过滤器提供了一种在操作级别自定义应用程序行为的方法。它们就像检查点&#…

Idea设置代理后无法clone git项目

背景 对于我们程序员来说&#xff0c;经常上github找项目、找资料是必不可少的&#xff0c;但是一些原因&#xff0c;我们访问的时候速度特别的慢&#xff0c;需要有个代理&#xff0c;才能正常的访问。 今天碰到个问题&#xff0c;使用idea工具 clone项目&#xff0c;速度特…

三、防御保护---防火墙安全策略篇

三、防御保护---防火墙安全策略篇 一、什么是安全策略二、安全策略的组成1.匹配条件2.动作3.策略标识 三、防火墙的状态检测和会话表1.会话表2.状态检测技术 四、ASPF--隐形通道五、用户认证1.用户认证的分类2.认证方式3.认证策略4.认证域 一、什么是安全策略 传统的包过滤防火…

计算机毕业设计 基于SpringBoot的车辆违章信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Android 中的动态应用程序图标

Android 中的动态应用程序图标 一、需求二、解决方案三、方案实现四、结论 一、需求 您可能遇到过那些可以实现巧妙技巧的应用程序 - 更改应用程序图标&#xff08;也许是在您的生日那天&#xff09;&#xff0c;然后无缝切换回常规图标。这种功能会激起你的好奇心&#xff0c…

websocket 通信协议

websocket是什么 答: 它是一种网络通信协议&#xff0c;是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 意思就是服务器可以主动向客户端推送信息&#xff0c;客户端也可以主动向服务器发送信息 属于服务器推送技术的一种. 为什么需要websocket? 疑问?…

Java 面试题之 IO(一)

字节流 文章目录 字节流InputStream&#xff08;字节输入流&#xff09;OutputStream&#xff08;字节输出流&#xff09; 文章来自Java Guide 用于学习如有侵权&#xff0c;立即删除 InputStream&#xff08;字节输入流&#xff09; InputStream用于从源头&#xff08;通常是…

【command】使用nr简化npm run命令

参考文章 添加 alias nrnpm run通过alias启动命令可以帮助我们节省运行项目输入命令的时间 $ cd ~ $ vim .bash_profile $ source ~/.bashrc

【51单片机Keil+Proteus8.9】门锁控制电路

门锁控制电路 二、设计思路 电路设计 1.电源部分&#xff1a;使用BATTERY为整个电路提供电源&#xff0c;可以在电路中加入一个电 源开关&#xff0c;以便控制电源的开启和关闭。 2.处理器部分&#xff1a;使用AT89C51芯片作为主处理器&#xff0c;通过编写程序实现门锁的 …

【Java IO 源码详解】: InputStream

本文主要从JDK 11 源码角度分析InputStream。 Java IO - 源码: InputStream InputStream 类实现关系InputStream 抽象类源码实现InputStreamFilterInputStreamByteArrayInputStreamBufferedInputStream 参考文章 InputStream 类实现关系 InputStream是输入字节流&#xff0c;具…

来聊聊大厂面试题:求Java对象的大小

写在文章开头 日常使用Java进行业务开发时&#xff0c;我们基本不关心一个Java对象的大小&#xff0c;所以经常因为错误的估算导致大量的内存空间在无形之间被浪费了&#xff0c;所以今天笔者就基于这篇文章来聊聊一个Java对象的大小。 你好&#xff0c;我叫sharkchili&#x…

网络体系结构 和网络原理之UDP和TCP

目录 网络分层 一. 应用层 http协议 二. 传输层 1. 介绍 2.UDP协议 (1)组成 (2)细节 3.TCP协议 (1)特性如下链接&#xff1a; (2)组成 (3)特点 三. 网络层 四. 数据链路层 1.介绍 2.以太网协议 3.mac地址和ip地址 五. 物理层 DNS 网络分层 一. 应用层 应用程序 现成的…

【深度优先搜索】【组合数学】【动态规划】1467.两个盒子中球的颜色数相同的概率

作者推荐 【动态规划】【字符串】【行程码】1531. 压缩字符串 本文涉及知识点 动态规划汇总 深度优先搜索 组合数学 LeetCode1467 两个盒子中球的颜色数相同的概率 桌面上有 2n 个颜色不完全相同的球&#xff0c;球上的颜色共有 k 种。给你一个大小为 k 的整数数组 balls …

数据写入HBase(scala)

package sourceimport org.apache.hadoop.hbase.{HBaseConfiguration, TableName} import org.apache.hadoop.hbase.client.{ConnectionFactory, Put} import org.apache.hadoop.hbase.util.Bytesobject ffff {def main(args: Array[String]): Unit {//hbase连接配置val conf …

c++连接mysql

c连接mysql 安装mysql以及c对应的库进入数据库&#xff0c;创建数据库&#xff0c;表&#xff0c;并新建管理员用户编写c代码编译运行&#xff0c;测试结果头文件解释 安装mysql以及c对应的库 sudo apt-get update sudo apt-get install mysql-server sudo apt-get install li…

2023年算法CDO-CNN-BiLSTM-ATTENTION回归预测(matlab)

2023年算法CDO-CNN-BiLSTM-ATTENTION回归预测&#xff08;matlab&#xff09; CDO-CNN-BiLSTM-Attention切诺贝利灾难优化器优化卷积-长短期记忆神经网络结合注意力机制的数据回归预测 Matlab语言。 切诺贝利灾难优化器Chernobyl Disaster Optimizer (CDO)是H. Shehadeh于202…