20240628每日前端---------解决vue项目滥用watch
主题
滥用watch。
名字解释
watch
例子
先看一个代码例子:
<template>{{ dataList }}
</template><script setup lang="ts">
import { ref, watch } from "vue";const dataList = ref([]);
const props = defineProps(["disableList", "type", "id"]);
watch(() => props.disableList,() => {// The logic based on disableList is very complex, and it computes a new list synchronouslyconst newList = getListFromDisabledList(dataList.value);dataList.value = newList;},{ deep: true }
);
watch(() => props.type,() => {// The logic based on type is very complex and computes a new list synchronouslyconst newList = getListFromType(dataList.value);dataList.value = newList;}
);
watch(() => props.id,() => {// Fetch dataList from the serverfetchDataList();},{ immediate: true }
);
</script>
在上面的示例中,当props.id被更新或者初始化时候,dataList会从服务器异步获取。
当disableList,type更新时,将同步计算新的 dataList。
代码逻辑流程图如下:

乍一看,上面的代码似乎很好,但是当不熟悉这个模块的新同事接手时,问题就出现了。
通常,在接管我们不熟悉的业务领域时,我们需要找到一个起点。
对于前端方面哈,这个起点肯定是浏览器中呈现的页面。
在 Vue 中,页面是从模板渲染的,因此识别模板中使用的变量及其来源可以帮助我们理解业务逻辑。
以变量disableList为例,追溯其来源通常可以明确业务逻辑。
在我们的例子中,来源是多种多样的,且来自多个来源。
首先,它通过 watch props.id 从服务器异步更新。
然后,它通过监听watch props.disableList 和 watch props.type 上实现同步更新。
此时,不熟悉业务的同事收到产品要求以更新检索逻辑时,必须首先熟悉其多个来源背后的逻辑。
在了解了逻辑之后,他们需要准确分析哪些应该修改以满足产品要求。
然而,在实践中,在维护别人的代码(尤其是复杂代码)时,我们通常不愿意修改现有代码,而是在上面添加我们自己的代码。
更改别人的复杂代码可能会引入错误,然后我们可能会受到指责。因此,我们通常的方法是添加另一个并实现最新的业务逻辑:
watch(() => props.xxx,() => {// Add the latest business logicconst newList = getListFromXxx(dataList.value);dataList.value = newList;}
);
经过几次迭代后,此文件变得杂乱无章,充斥着大量语句,从而导致“屎山代码”。当然,在某些情况下,这种编码风格可能是故意确保自己在团队中的地位,因为没有人敢碰这个复杂的代码块。。。。。。。
如何解决问题 computer
首先我们先明白正确的可维护的变量流程

dataList在模板中,同步更新,数据异步从服务器获取。
整个过程可以可视化为单个线程。当新开发人员加入团队迭代相关业务时,只需要了解最新的产品需求是建议在同步阶段还是异步阶段修改代码,然后在对应阶段添加最新的代码即可。
基于以上逻辑,代码简写如下:
<template>{{ renderDataList }}
</template>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
const props = defineProps(["disableList", "type", "id"]);
const dataList = ref([]);
const renderDataList = computed(() => {// Calculate the list based on disableListconst newDataList = getListFromDisabledList(dataList.value);// Calculate the list based on typereturn getListFromType(newDataList);
});
watch(() => props.id,() => {// Fetch dataList from the serverfetchDataList();},{immediate: true,}
);
</script>
在上面中,我们不再渲染dataList变量,而是渲染renderDataList变量。 是包含dataList的所有同步相关逻辑的 。代码逻辑流程图如下:

这样,如果有新需求变量变更,修改逻辑的演示如下:
const renderDataList = computed(() => {// Add the latest business logic from the productconst xxxList = getListFromXxx(dataList.value);// Calculate the list based on disableListconst newDataList = getListFromDisabledList(xxxList);// Calculate the list based on typereturn getListFromType(newDataList);
});
结论
本文介绍了两种主要的使用场景:一种是当被监视的值发生变化并需要同步更新要渲染的值时,另一种是当值发生变化并需要从服务器异步获取要渲染的值时。
如果同步和异步更新都不加区别地写在watch中,那么接手的后续维护者会发现梳理相关逻辑非常痛苦。
这是因为到处都在更新值,完全不清楚在哪里添加最新的业务逻辑。
随着时间的流逝,如果代码变成一堆实例,可维护性就会恶化。
我们的优化解决方案是将所有同步更新的代码堆叠到renderDataList
后续维护者只需要决定新业务是否是同步更新,那么他们就应该在dataList中写入新的业务逻辑。
如果是对 renderDataList的异步更新,则应将新的业务逻辑写入 computed中。
题外话
那么vue中 watch 和computer的区别你知道了吗?
1、缓存机制:
computed属性具有缓存机制。只有当其依赖的数据发生变化时,它才会重新计算。如果依赖的数据没有变化,那么它将直接返回之前缓存的结果。这种缓存机制可以提高性能,避免不必要的计算。
watch属性则没有缓存机制。每当它所监听的数据发生变化时,它都会触发相应的操作,不论这个操作是否已经被执行过。
2、异步支持:
computed不支持异步操作。如果computed内部包含异步操作,它将无法正常工作,因为它依赖于同步的响应式依赖。
watch则支持异步操作。在watch的回调函数中,你可以执行任何异步操作,如网络请求等。
3、执行时机:
computed属性在依赖的数据发生变化时才会执行。如果数据没有变化,那么它将不会执行。
watch属性则会在所监听的数据发生变化时立即执行其回调函数。
4、数据类型:
computed主要用于处理复杂的逻辑运算,返回一个新的属性值。它通常用于处理一些需要通过计算得到的数据,如根据购物车中的商品数量和单价计算出总价等。
watch则主要用于监听数据的变化,并在数据变化时执行一些副作用或异步操作。例如,根据用户输入的地址获取并显示地图信息等。
5、参数和返回值:
computed属性通常不需要额外的参数,它直接返回一个新的属性值。同时,它也可以定义一个setter函数来修改它的值。
watch属性则需要两个参数:newVal(新值)和oldVal(旧值)。在watch的回调函数中,你可以使用这两个参数来执行相应的操作。
6、性能:
由于computed具有缓存机制,因此它在处理大量数据或复杂计算时通常具有更好的性能。
watch则没有缓存机制,因此在处理大量数据或频繁变化的数据时可能会导致性能问题。
相关文章:
20240628每日前端---------解决vue项目滥用watch
主题 滥用watch。 名字解释 watch 例子 先看一个代码例子: <template>{{ dataList }} </template><script setup lang"ts"> import { ref, watch } from "vue";const dataList ref([]); const props defineProps([&q…...
【LLM 评估】GLUE benchmark:NLU 的多任务 benchmark
论文:GLUE: A Multi-Task Benchmark and Analysis Platform for Natural Language Understanding ⭐⭐⭐⭐ arXiv:1804.07461, ICLR 2019 Site: https://gluebenchmark.com/ 文章目录 一、论文速读二、GLUE 任务列表2.1 CoLA(Corpus of Linguistic Accep…...
Go线程调度器
基本结构 字段gcwaiting、stopwait和stopnoted都是串行运行时任务执行前后的辅助协调手段 gcwaiting字段的值用于表示是否需要停止调度 在停止调度前,该值会被设置为1在恢复调度之前,该值会被设置为0这样做的作用是,一些调度任务在执行时只…...
使用 fvm 管理 Flutter 版本
文章目录 Github官网fvm 安装Mac/Linux 环境Windows 环境 fvm 环境变量fvm 基本命令 Github https://github.com/leoafarias/fvmhttps://github.com/flutter/flutter 官网 https://fvm.app/ fvm 安装 Mac/Linux 环境 Install.sh curl -fsSL https://fvm.app/install.sh …...
若依-前后端分离项目学习
★★★★★省流 直接看第一集和最后一集★★★★★ 第一天(6.24) 具体参考视频 b站 楠哥教你学Java 【【开源项目学习】若依前后端分离版,通俗易懂,快速上手】 https://www.bilibili.com/video/BV1HT4y1d7oA/?shar…...
使用adb shell getprop命令获取Android设备的属性
常用属性获取: adb shell getprop ro.build.version.emui —查询EMUI版本 adb shell getprop ro.product.brand —查询手机品牌 adb shell getprop ro.product.name --查询设备名称 adb shell getprop ro.serialno —查询设备序列号 获取手机系统信息( CPU,厂商…...
LNMP环境部署指南
本文档将指导您在CentOS 6.5上部署LNMP(Linux、Nginx、MySQL、PHP)环境。 系统环境 系统平台:CentOS release 6.5 安装前准备 在安装LNMP之前,您需要安装一些编译器和依赖包。 必备编译器和工具 #安装gcc、gcc-c编译器&#…...
[stm32]温湿度采集与OLED显示
一、I2C总线协议 I2C(Inter-integrated circuit )是一种允许从不同的芯片或电路与不同的主芯片通信的协议。它仅用于短距离通信,是一种用于两个或多个设备之间进行数据传输的串行总线技术,它可以让你在微处理器、传感器、存储器、…...
大模型知识库的使用
大模型知识库的使用通常涉及以下几个方面,使用大模型知识库可以提高信息检索的准确性和效率,促进知识的传播和应用。同时,也需要关注知识库的质量和更新,以确保提供的知识是准确和可靠的。北京木奇移动技术有限公司,专…...
Docker - Oracle Database 23ai Free
博文目录 文章目录 说明命令NavicatSYSTEMPDBADMIN 扩展公共用户本地用户 说明 Oracle 官方镜像仓库 Database 23ai Free | Oracle Docker 官方没有提供 Oracle Database 相关镜像, 但是 Oracle 官方镜像仓库有提供, 打开上面的链接, 选择 Database, 选择合适的版本, 如 enter…...
spring常用方法
1. 读取配置文件信息 方式一: // 获取文件路径 String fileName "application.yaml"; String filePath this.getClass().getClassLoader().getResource(fileName).getPath();BufferedReader bufferedReader new BufferedReader(new FileReader(path)…...
虚拟机能装在移动硬盘里吗安全吗 PD虚拟机迁移到移动硬盘的方法
虚拟机技术的迅速发展为用户提供了更为灵活的跨系统办公方案。许多用户希望在不同的电脑设备上运行相同的虚拟机,同时带来的也有一个问题:虚拟机能否装在移动硬盘里?针对用户的疑问,接下来给大家介绍虚拟机能装在移动硬盘里吗&…...
刷算法Leetcode---7(二叉树篇)(前中后序遍历)
前言 本文是跟着代码随想录的栈与队列顺序进行刷题并编写的 代码随想录 好久没刷算法了,最近又开始继续刷,果然还是要坚持。 二叉树的题目比之前多了好多,就多分几次写啦~ 这是力扣刷算法的其他文章链接:刷算法Leetcode文章汇总 …...
AliyunOS安装Node.js
方法1:dnf软件包安装工具自动安装 最方便的安装方式是通过系统的dnf工具,我测试使用的AliyunOS的版本是Alibaba Cloud Linux 3.2104,具体流程如下: dnf module list nodejs #列出服务器中可以使用的所有nodejs版本确定下来希望安…...
three.js - MeshPhongMaterial材质(实现玻璃水晶球效果)
1、概念 phong网格材质:Mesh - Phong - Material 一种用于具有镜面高光的光泽表面的材质。 它可以模拟,具有镜面高光的光泽表面,提供镜面反射效果。 MeshPhongMaterial: MeshPhongMaterial是一种基于Phong光照模型的材质&#…...
笔记本电脑安装CentOS
正文共:1234 字 24 图,预估阅读时间:2 分钟 前面我们对VPP进行了多次介绍(羡慕!大佬的VPP能达到180G性能,而我的却只有13.5G),可以发现他的很多优点,但是我们也可以发现它…...
ssh转发功能入门
端口转发概述 端口转发,能够将其他TCP端口的网络数据通过SSH链路转发,并且提供了ssh的加密和解密的服务。 ssh端口转发有如下这些优点: 提供了ssh的加密传输,利于安全能够突破防火墙限制 目前ssh端口转发有如下几种方式&#x…...
Listary(Windows 文件搜索工具)专业版值得购买吗?
说到经典的国货软件,有一款 Win 软件是一定绕不过去的。它就是知名的本地文件搜索工具 Listary! 便捷的文件搜索窗口;快捷操作的体验;与系统更匹配的外观设计;更智能的排序和更可靠的索引。 便捷的文件搜索窗口 紧凑…...
面试突击指南:Java基础面试题2
面向对象和集合 1. 面向对象和面向过程的区别 面向过程:面向过程的编程方式是分析解决问题的步骤,然后用函数把这些步骤一步一步地实现,并在使用的时候逐个调用。这种方式性能较高,因此在单片机和嵌入式开发中经常采用面向过程开发。 面向对象:面向对象的编程方式是把问…...
MySQL快速安装(mysql8.0.30区别之前yum安装)
目录 一.初始化环境并解压 二.创建程序用户管理 三.修改mysql目录和配置文件的权限 四.修改配置文件 五.设置环境变量,申明/宣告mysql命令便于系统识别 六.初始化数据库 七.设置系统识别,进行操作 八.初始化数据库密码 九.用户并设置密码 十.赋…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
