news 2026/1/21 15:35:15

性能优化 - Vue 日常实践优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
性能优化 - Vue 日常实践优化

在 Vue 应用开发过程中,通过合理使用框架特性、避免性能陷阱、优化组件设计等方式,从代码层面提升应用性能。

优化实践

使用内置 API 完成需求

JIT 是浏览器中的 JavaScript 引擎在运行时,把热点 JavaScript 代码即时编译为机器码,从而提高执行性能的一种机制。

Chrome 浏览器 JIT 指内置的 JavaScript 引擎 V8 的即时编译机制。

使用 DOM API / BOM API / Vue API 完成开发,DOM API / BOM API / Vue API 通常有对应的优化算法,必要时或节约开发成本时再使用第三方工具类库辅助。

  • API 底层都是基于 V8 引擎,相比 JS 层 JIT 编译执行而言,基于 C++ 的 V8 会更快。
  • sort会根据情况采用归并或者插入排序(小数组采用插入,大数组采用归并或者是归并 + 插入的混合排序方案),相比手动实现的 JS 排序功能更优。
  • 遍历时使用for...of/for代替for...infor...in语义需要收集对象自身的枚举属性,然后再去遍历原型链上的属性,过滤掉不可枚举的属性值,然后处理属性遮蔽问题,最终动态决定遍历结果,这个无法预测的枚举流程是无法被跳过的,在数组遍历时只能执行慢路径查找。
// 推荐:使用 for...of 或 for 循环constarr=[1,2,3,4,5];for(constitemofarr){console.log(item);}// 或使用传统 for 循环for(leti=0;i<arr.length;i++){console.log(arr[i]);}// 避免:使用 for...in 遍历数组(性能较差)for(constindexinarr){console.log(arr[index]);}

避免非必要响应式

避免将非响应式实例声明为响应式,尤其注意不要将插件实例声明为响应式,在 Vue2 中会由于深度递归响应,导致大量内存被占用,严重会出现假死的情况。
在 Vue3 中,可以使用shallowRefshallowReactive来避免非必要的响应逻辑。

// ❌ 将插件实例声明为响应式exportdefault{data(){return{// Vue2 会深度递归处理,导致性能问题echart:null,moment:moment,};},mounted(){this.echart=echart.init();}};// ✅ 使用 Object.freeze 或直接挂载到 thisexportdefault{data(){return{// 使用 Object.freeze 冻结对象,避免响应式处理// Vue 处理响应式之前会去判断 configurable 描述符是否可用,不可用不会进行响应式处理axios:Object.freeze(axios),};},created(){// 或直接挂载到实例上,不放入 datathis.axios=axios;},};

Keepalive 缓存

使用<keep-alive>缓存组件,根据需求进行缓存,小型项目可以直接进行RouterView级别缓存,大型项目指定对大型组件的缓存,同时通过max指定最大缓存组件数,注意要在activateddeactivated中完成组件的唤醒和卸载处理。

<!-- 小型项目:RouterView 级别缓存 --><template><keep-alive:max="10"><router-view/></keep-alive></template><!-- 大型项目:指定组件缓存 --><template><keep-alive:include="['ComponentA','ComponentB']":max="5"><component:is="currentComponent"/></keep-alive></template><script>exportdefault{name:"ComponentA",activated(){// 组件被激活时执行// 完成定时器、事件、数据请求this.setTimers();this.refreshData();},deactivated(){// 组件被停用时执行// 销毁定时器,事件,避免内存泄漏和逻辑冲突this.clearTimers();},};</script>

v-if 和 v-show

频繁切换避免使用v-if,使用v-show,由于v-show会导致代码不太美观,可以的话通过<component :is="bindComponent">或者v-if结合<keep-alive>实现类似的逻辑。

<template><!-- ❌ v-if 会销毁和重建组件 --><divv-if="showComponent">组件内容</div><!-- ✅ v-show 只切换 display 样式 --><divv-show="showComponent">组件内容</div><!-- ✅ 使用 component 动态组件 + keep-alive 组合,保持代码美观,配合异步组件优化首次渲染体积,基于 keep-alive 实现异步组件缓存策略 --><keep-alive><component:is="currentComponent"/></keep-alive></template><script>exportdefault{components:{// Vue3 用 defineAsyncComponent 封装引入ComponentA:()=>import("./components/componentA"),ComponentB:()=>import("./components/componentB"),},data(){return{showComponent:true,currentComponent:"ComponentA",};},};</script>

Computed 缓存

计算内容可以用computed计算属性去缓存,computed会在依赖属性更新触发视图更新时,才会根据dirty标志位判断依赖属性是否更新,决定计算新值还是获取缓存值。

<template><div><p>总价:{{ totalPrice }}</p><p>折扣价:{{ discountPrice }}</p></div></template><script>exportdefault{data(){return{items:[{price:10,quantity:2},{price:20,quantity:3},],discount:0.8,};},computed:{// ✅ 依赖变化时才重新计算,否则使用缓存totalPrice(){returnthis.items.reduce((sum,item)=>sum+item.price*item.quantity,0);},// 依赖 totalPrice 计算结果,totalPrice 缓存时 discount 不会重复计算discountPrice(){returnthis.totalPrice*this.discount;},},// ❌ 不推荐:使用 methods 每次都会重新计算methods:{getTotalPrice(){returnthis.items.reduce((sum,item)=>sum+item.price*item.quantity,0);},},};</script>

内部创建和销毁

销毁监听器、定时器、实例,避免出现内存泄漏影响性能问题。

<script>exportdefault{data(){return{timer:null,resizeHandler:null,};},mounted(){// 创建定时器this.timer=setInterval(()=>{console.log("定时任务");},1000);// 小技巧:通过 AbortController 可以同时销毁多个事件监听器this.controller=newAbortController();window.addEventListener("scroll",this.scrollHandler,{signal:this.controller.signal,});window.addEventListener("resize",this.resizeHandler,{signal:this.controller.signal,});// 三方插件初始化this.thirdPlugin=plugin.init();},methods:{resizeHandler(){// resize 事件},scrollHandler(){// scroll 事件},},beforeDestroy(){// ✅ 销毁定时器if(this.timer){clearInterval(this.timer);this.timer=null;}// ✅ 销毁事件监听if(this.controller){this.controller.abort();this.controller=null;}// ✅ 销毁插件实例if(this.thirdPlugin){// 先看三方插件内部是否有销毁 API 主动执行,避免插件内部引用未销毁导致泄漏this.thirdPlugin.destroy();this.thirdPlugin=null;}},};</script>

异步组件

Vue-Router 和 Vue 通过异步组件方式按需引入,必要时再进行加载。

但是要避免过度拆分,当组件拆分前请求成本(请求耗时、请求体积、是否重复) > 组件拆分后的请求成本时,再考虑进行拆分。

importHomefrom"@/views/Home.vue";// Vue Router 异步组件constroutes=[{path:"/home",// 首页不推荐异步逻辑,避免首页加载白屏component:Home,},{path:"/large-page",// ✅ 使用 webpackChunkName 指定 chunk 名称,避免过渡拆包,可以把同个页面下的子路由都集中在webpackChunk中加载,也可以按需拆分component:()=>import(/* webpackChunkName: "large-page" */"@/views/LargePage.vue"),},];// Vue 组件异步加载exportdefault{components:{// ✅ 异步组件:按需加载HeavyComponent:()=>import("@/components/HeavyComponent.vue"),// ✅ 带加载状态和错误处理, Vue3 使用 defineComponent APIAsyncComponent:()=>({component:import("@/components/AsyncComponent.vue"),loading:LoadingComponent,error:ErrorComponent,delay:200,// 延迟显示 loadingtimeout:3000,// 超时时间}),},};

Vue 官方优化实践

  • Vue.js 官方文档 - 性能优化:提供关于 v-once 和函数式组件的优化方案等。
  • Vue2 Cookbook:关于 Vue2 的最佳实践。

总结

  • 使用内置 API:优先使用 DOM API / BOM API / Vue API 完成开发,这些 API 基于 V8 引擎优化,性能优于手动实现的 JavaScript 代码。遍历时使用for...of/for代替for...in,避免慢路径查找。
  • 避免非必要响应式:避免将插件实例等非响应式对象声明为响应式,在 Vue2 中会由于深度递归响应导致性能问题。使用Object.freeze冻结对象或直接挂载到实例上,避免响应式处理。
  • 组件缓存:使用<keep-alive>缓存组件,小型项目可以直接进行RouterView级别缓存,大型项目指定对大型组件的缓存,同时通过max指定最大缓存组件数。注意要在activateddeactivated中完成组件的唤醒和卸载处理。
  • 条件渲染优化:频繁切换避免使用v-if,使用v-show。可以通过<component :is="bindComponent">或者v-if结合<keep-alive>实现类似的逻辑,保持代码美观的同时优化性能。
  • 计算属性缓存:使用computed计算属性缓存计算结果,computed会在依赖属性更新触发视图更新时,根据dirty标志位判断是否重新计算,否则使用缓存值。
  • 资源清理:及时销毁监听器、定时器、实例,避免内存泄漏。可以使用AbortController同时销毁多个事件监听器,对于三方插件需要主动调用销毁 API。
  • 异步组件:通过异步组件方式按需引入,优化首屏加载速度。但要避免过度拆分,需要权衡组件拆分前后的请求成本(请求耗时、请求体积、是否重复)。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/14 10:14:29

5分钟验证PCIE4.0与3.0的性能差异

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个极简的PCIE性能测试工具原型&#xff0c;功能包括&#xff1a;1)文件传输速度测试 2)延迟测量 3)带宽利用率监控。使用Python实现&#xff0c;输出简洁的对比报告&#xf…

作者头像 李华
网站建设 2026/1/20 16:19:14

语言模型作为模拟器:面向复杂决策的少样本情境学习理论框架

语言模型作为模拟器&#xff1a;面向复杂决策的少样本情境学习理论框架摘要&#xff1a; 大型语言模型在少样本情境学习中所展现的复杂任务处理能力&#xff0c;超越了传统监督学习的范式。本文提出一个理论框架&#xff0c;将先进的语言模型重新概念化为基于文本的概率世界模拟…

作者头像 李华
网站建设 2026/1/20 20:26:18

用OMNIBOX快速构建搜索原型:5分钟教程

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个基于OMNIBOX的快速搜索原型工具。要求&#xff1a;1. 提供简单的配置界面&#xff1b;2. 支持自定义数据源&#xff08;如API或本地文件&#xff09;&#xff1b;3. 实现基…

作者头像 李华
网站建设 2026/1/20 20:23:45

从CIH到AI幽灵:病毒从破坏到隐蔽的进化之路

从CIH到AI幽灵&#xff1a;病毒从破坏到隐蔽的进化之路引言&#xff1a;两个时代的病毒图景1999年4月26日&#xff0c;全球数十万台计算机同时瘫痪。CIH病毒&#xff08;又名“切尔诺贝利病毒”&#xff09;在这一天被触发&#xff0c;它不仅删除硬盘数据&#xff0c;更首次实现…

作者头像 李华
网站建设 2026/1/20 16:25:22

传统VS现代:JSTACK分析效率提升10倍的秘密

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个JSTACK分析效率对比工具&#xff0c;功能包括&#xff1a;1. 提供5组真实JSTACK日志样本 2. 传统分析方法的步骤模拟 3. AI自动化分析流程演示 4. 生成耗时和准确率的对比…

作者头像 李华
网站建设 2026/1/20 17:43:52

5分钟搞定:用Python快速处理Excel合并单元格

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个Python脚本生成器&#xff0c;用户通过简单界面设置合并需求&#xff08;如按某列值合并相邻相同内容的行&#xff09;&#xff0c;系统自动生成可执行的Python代码。支持…

作者头像 李华