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

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

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

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

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

基础写法:

html 复制代码
<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 属性,提前计算好需要的数据,避免每次都执行复杂的计算。

html 复制代码
<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 都可以控制组件或元素的显示,但如果用得不对,也会影响性能。

场景示例:

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

html 复制代码
<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

html 复制代码
<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 只是切换元素的 CSS display,不会频繁销毁和重建 DOM,适合频繁切换但数量有限的场景

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

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

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

基础写法:

html 复制代码
<template>
  <img :src="imageSrc" />
</template>

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

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

优化写法:图片懒加载

html 复制代码
<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 是监听数据变化的常用方式,但如果用得不当,会导致多次不必要的计算和请求,增加性能开销。

基础写法:

html 复制代码
<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 变化时都会触发请求,尤其是输入法弹出时,会多次触发请求。

优化写法:使用防抖

html 复制代码
<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 中,每次渲染组件时,都会重新绑定事件。如果绑定事件的元素很多,性能开销就会加大,尤其是在动态生成的列表中。

基础写法:

html 复制代码
<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 都会绑定一个新的事件处理函数,造成不必要的内存开销。

优化写法:事件委托

html 复制代码
<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>

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

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

相关推荐
chenhdowue2 小时前
vue 表格 vxe-table 高亮行支持取消操作
vue.js·vxe-table
CHU7290352 小时前
随时随地学新知——线上网课教学小程序前端功能详解
前端·小程序
清粥油条可乐炸鸡2 小时前
motion入门教程
前端·css·react.js
这是个栗子2 小时前
【Vue3项目】电商前台项目(四)
前端·vue.js·pinia·表单校验·面包屑导航
前端Hardy2 小时前
Electrobun 正式登场:仅 12MB,JS 桌面开发迎来轻量化新方案!
前端·javascript·electron
树上有只程序猿2 小时前
新世界的入场券,不再只发给程序员
前端·人工智能
confiself2 小时前
deer-flow前端分析
前端
刘宇琪2 小时前
Vite 生产环境代码分割与懒加载优化
前端
叫我一声阿雷吧2 小时前
JS 入门通关手册(20):构造函数与原型:JS 面向对象第一课
开发语言·javascript·前端开发·前端面试·构造函数·js进阶·js面向对象