当前位置: 首页 > news >正文

除了防抖和节流,还有哪些 JS 性能优化手段?


防抖和
节流大家都用过,但 JS 性能优化其实不止这两种。在日常开发里,有很多实用的方法,可以让页面更顺畅。

于是我整理了几个常用的 vue 性能优化写法,自己用起来也很顺手。

1. 避免模板中的重复计算

我以前喜欢直接在模板中写一些计算逻辑,虽然它能快速实现需求,但如果不小心,可能会影响性能。尤其是当组件频繁更新时,重复计算的开销就会显现出来。

基础写法:

<template> <div v-for="item in list" :key="item.id"> 商品:{{ item.name }} 价格:{{ formatPrice(item.price) }} </div> </template> <script setup> import { ref } from "vue" const list = ref([ { id: 1, name: "键盘", price: 1999 }, { id: 2, name: "鼠标", price: 299 }, { id: 3, name: "显示器", price: 3999 } ]) const formatPrice = (price) => { return "¥" + (price / 100).toFixed(2) } </script>

问题:每次渲染时,formatPrice会重新计算,假如列表有几百个条目,这个性能损耗就会变得明显。

优化写法:

可以使用
Vue3 的computed属性,提前计算好需要的数据,避免每次都执行复杂的计算。

<template> <div v-for="item in formattedList" :key="item.id"> 商品:{{ item.name }} 价格:{{ item.priceText }} </div> </template> <script setup> import { ref, computed } from "vue" const list = ref([ { id: 1, name: "键盘", price: 1999 }, { id: 2, name: "鼠标", price: 299 }, { id: 3, name: "显示器", price: 3999 } ]) const formattedList = computed(() => { return list.value.map(item => ({ ...item, priceText: "¥" + (item.price / 100).toFixed(2) })) }) </script>

优化效果:只有list数据发生变化时,formattedList才会重新计算,避免了每次渲染时都重新格式化价格,提升了性能。

2. 合理使用
v-if 和 v-show

在 Vue3 中,v-ifv-show都可以控制组件或元素的显示,但如果用得不对,也会影响性能。

场景示例:

假设有一个选项卡组件,用户频繁切换内容:

<template> <button @click="tab = 1">Tab 1</button> <button @click="tab = 2">Tab 2</button> <div v-if="tab === 1">内容 1</div> <div v-if="tab === 2">内容 2</div> </template> <script setup> import { ref } from "vue" const tab = ref(1) </script>

问题:每次切换 tab 时,v-if都会销毁和重建对应 DOM,如果内容复杂或包含子组件,性能开销明显。

优化写法:使用v-show

<template> <button @click="tab = 1">Tab 1</button> <button @click="tab = 2">Tab 2</button> <div v-show="tab === 1">内容 1</div> <div v-show="tab === 2">内容 2</div> </template>

优化效果v-show只是切换元素的 CSSdisplay,不会频繁销毁和重建 DOM,适合频繁切换但数量有限的场景

如果是初次渲染开销大、切换不频繁,用v-if;如果是频繁切换,用v-show。合理选择可以明显提高性能。

3. 懒加载
:先渲染用户可见部分

懒加载是一种非常有效的技术,可以让页面内容只有在用户滚动到该部分时才加载,提升首屏加载速度,减少不必要的请求。

基础写法:

<template> <img :src="imageSrc" /> </template> <script setup> const imageSrc = "https://example.com/large-image.jpg" </script>

问题:直接在组件加载时就请求了图片,导致首屏加载时间增加。

优化写法:图片懒加载

<template> <img v-lazy="imageSrc" /> </template> <script setup> import { ref } from "vue" import { useIntersectionObserver } from "@vueuse/core" const imageSrc = ref("https://example.com/large-image.jpg") // 使用 @vueuse/core 的 useIntersectionObserver 来懒加载图片 useIntersectionObserver(imageRef, () => { imageRef.src = imageSrc.value }) </script>

优化效果:只有当图片进入视口时才会开始加载,减少了首屏的资源加载,提高页面加载速度。

4. 避免过度使用 watch

在 Vue 中,watch是监听数据变化的常用方式,但如果用得不当,会导致多次不必要的计算和请求,增加性能开销。

基础写法:

<template> <input v-model="searchQuery" placeholder="搜索" /> </template> <script setup> import { ref, watch } from "vue" const searchQuery = ref("") watch(searchQuery, (newQuery) => { // 每次输入都会发请求 fetch(`/api/search?q=${newQuery}`) }) </script>

问题:每次searchQuery变化时都会触发请求,尤其是输入法弹出时,会多次触发请求。

优化写法:使用防抖

<template> <input v-model="searchQuery" placeholder="搜索" /> </template> <script setup> import { ref, watch } from "vue" const searchQuery = ref("") let timeout watch(searchQuery, (newQuery) => { clearTimeout(timeout) timeout = setTimeout(() => { fetch(`/api/search?q=${newQuery}`) }, 500) // 防抖:500ms后才发送请求 }) </script>

优化效果:只有在用户停止输入 500 毫秒后才会发起请求,避免了过于频繁的请求。

5. 避免重复绑定事件

在 Vue3 中,每次渲染组件时,都会重新绑定事件。如果绑定事件的元素很多,性能开销就会加大,尤其是在动态生成的列表中。

基础写法:

<template> <div v-for="item in list" :key="item.id"> <button @click="handleClick(item.id)">点击</button> </div> </template> <script setup> const handleClick = (id) => { console.log("点击按钮", id) } </script>

问题:每个button都会绑定一个新的事件处理函数,造成不必要的内存开销。

优化写法:事件委托

<template> <div @click="handleClick"> <div v-for="item in list" :key="item.id"> <button>{{ item.name }}</button> </div> </div> </template> <script setup> const handleClick = (e) => { if (e.target.tagName === 'BUTTON') { console.log('点击按钮', e.target.innerText) } } </script>

优化效果:通过事件委托,将事件绑定到父元素上,避免了为每个按钮都单独绑定事件,大大减少了内存开销。

以上这些写法都是我平时在项目里用的,实用又好操作。如果你在开发中有自己的优化方法,也欢迎在评论区分享,我们一起讨论。

http://www.jsqmd.com/news/514126/

相关文章:

  • 【搜索与图论】DFS算法(深度优先搜索)
  • 避坑指南:ESP-IDF 4.3下DPP配网常见的3个错误(附事件组调试方法)
  • 用过才敢说!全领域适配的AI论文写作神器 —— 千笔AI
  • Qwen-Image部署教程:RTX4090D+Qwen-Image镜像构建企业级多模态API服务
  • 3.3 在代码中验证与避免误差
  • Lumerical INTERCONNECT实战:5分钟搞定自相位调制(SPM)仿真(附参数配置截图)
  • Qwen-Image定制镜像部署案例:RTX4090D支撑Qwen-VL与Stable Diffusion联动实现图文互生
  • 云容笔谈应用场景:独立设计师用AI生成苏绣/缂丝/云锦纹样设计初稿
  • STM32HAL库驱动DHT11温湿度传感器:从零开始的避坑实战(附完整代码)
  • OpenClaw语音交互扩展:Qwen3-32B对接Whisper实现语音指令控制
  • Pixel Dimension Fissioner惊艳效果展示:10组高创意文案裂变真实对比图
  • 用PID控制器模拟房间温度控制:MATLAB与Simulink的奇妙之旅
  • 灵毓秀-造相Z-Turbo案例展示:快速生成精美古风插画
  • 解决 GPT-5.4 废话多的问题
  • 用STM32F103C8T6复刻开源手表WATCHX-NWATCH:从B站视频到桌面摆件的DIY全记录
  • Qwen-Image效果展示:商品图→属性提取→文案生成全流程惊艳效果实录
  • 真的太省时间!当红之选的降AI率软件 —— 千笔·专业降AI率智能体
  • LongCat-Image-Editn效果展示:中英双语一句话改图,原图非编辑区域纹丝不动
  • 别再手动写API了!用Flask+ngrok快速给MySQL做个Dify专用接口(附完整代码)
  • Linux nc命令实战:5个网络工程师常用的Netcat技巧(附真实案例)
  • OWL ADVENTURE环境配置详解:Anaconda虚拟环境下的依赖管理
  • 提示工程架构师必读:研发效能提升的6大关键点
  • Pixel Dimension Fissioner智能助手:客服话术动态裂变与风格适配应用
  • 数字货币做市避坑指南:Avellaneda模型在7*24市场的5个调参技巧
  • Keil5+C++玩转STM32:从点灯到串口通信的完整实战指南(附避坑技巧)
  • 基于STM32的汽修厂多参数环境监测与智能联动系统
  • 空间认知成为核心生产力:智慧仓储的下一代发展路径
  • CVE-2016-4437 Apache Shiro反序列化漏洞复现
  • Linux 下 IDEA 开发环境一站式部署与疑难排解
  • 企业内网搞定Kubeflow v1.8:从镜像拉取到Harbor仓库配置的完整避坑记录