Vue开发中的十二条性能优化技巧
时间:2023-03-16 10:58:31
科技观察
性能优化是每个开发者都会遇到的问题,尤其是现在越来越注重体验,在竞争越来越激烈的环境下,对于我们开发者来说,更是远远不足以完成迭代并使功能良好。最重要的是把产品做好,让更多的人愿意用,让用户用得更舒心。这不也是我们开发者的价值和能力吗?化身呢?关注性能问题,优化产品体验,比修复几个无伤大雅的bug更有价值优化1.不做响应式,比如会员列表,产品列表等,只是纯数据展示,没有任何动态变化,有不需要对数据做响应式处理,可以大大提高渲染速度。例如,使用Object.freeze()冻结一个对象。MDN的描述是该方法冻结的对象不可修改;即不能向该对象添加新属性,不能删除已有属性,也不能修改对象已有属性的可枚举性。可配置性、可写性、已有属性的值不可修改,对象原型不可修改"/api/users");this.userList=Object.freeze(users);}};Vue2的响应式源码地址:src/core/observer/index.js-第144行是这样的{return}...}可以看到configurable一开始就判断为false,没有响应处理直接返回configurable如果为false,说明这个属性不能修改,冻结对象的configurable为错误的。在Vue3中,增加了一个响应式标志来标记目标对象类型。2.如果虚拟滚动是一长串大数据,所有渲染如果一次创建过多的DOM,会很卡。这时候可以使用虚拟滚动,只渲染一小部分内容(包括可见区域),然后在滚动的时候,不断替换可见区域的内容来模拟滚动。参考vue-virtual-scroller,vue-virtual-scroll-list的原理是监听滚动事件,动态更新要显示的DOM,并计算视图中的位移,这也意味着在滚动过程中需要实时计算,具有一定的成本,所以如果数据量不大2.v-for遍历避免同时使用v-if为什么要避免同时使用v-for和v-if在Vue2中,v-for有一个更高的优先级,所以编译时会遍历所有list元素生成虚拟DOM,然后通过v-if判断进行渲染,这样会造成性能上的浪费,因为我们希望不满足的虚拟DOMVue3中不会生成条件。v-if的优先级更高,意味着当判断条件是v-for遍历的列表中的属性时,v-if获取不到。因此,在一些需要同时使用的场景下,可以通过计算属性来过滤列表,如下3.列表使用唯一键.例如,如果有一个列表,我我们需要在中间插入一个元素,如果不使用key或者使用index作为key会怎样呢?我们先来看图。图中的li1和li2不会重新渲染。这个没有争议,但是li3、li4、li5都会重新渲染,因为当不使用key或者list的index作为key时,每个元素对应的位置关系是不同的。它是索引。上图的结果直接导致插入的元素和后面所有元素的对应位置关系发生变化。因此,在补丁过程中,所有这些都会被更新和重新渲染。这不是我们想要的。我们想要的是在不改变其他四个元素的情况下渲染添加的元素,所以不要重新渲染。在使用uniquekey的情况下,每个元素对应的位置关系为key,我们看一下使用uniquekeyvalue的情况,这样图中的li3和li4就不会重新渲染了,因为元素内容没有变化,对应的位置关系也没有变化。这就是为什么v-for一定要写一个key,开发中不建议使用数组的索引作为key。4、使用v-show复用DOMv-show:渲染组件,然后将组件的显示更改为block或nonev-if:渲染或不渲染组件,所以对于可以频繁改变条件的场景,使用v-show节省性能,尤其是DOM结构越复杂,好处越大。不过它也有缺点,就是v-show一开始,会渲染该分支内的所有组件,并执行相应的生命周期钩子函数,而v-if只会加载命中的组件判断条件,所以需要根据不同的场景使用合适的指令,比如下面用v-show复用DOM,比v-if/v-else
原理就是用v-if在条件变化的时候触发diff更新,如果发现新旧vnode不一致,就会把旧的整个vnode去掉,然后重新创建一个新的vnode,然后再创建一个newmy-components组件,然后经过组件初始化、render、patch等过程,当v-show的条件发生变化时,新旧vnode是一致的,所以不会Ex执行删除和创建等一系列过程。5、无状态组件的函数式组件对于一些纯展示组件,没有响应式数据,没有状态管理,没有生命周期钩子函数,我们可以将它们设置为函数式组件。提高渲染性能,因为它会被当作一个函数来处理,所以开销很低。原理是在patch过程中,对于功能组件render生成的虚拟DOM,不会有递归的子组件初始化过程,所以渲染开销会很低。很多都可以接受props,但是因为不会创建实例,所以不能在内部使用this.xx获取组件属性,写法如下
//或Vue.component('my-component',{functional:true,//表示该组件是函数式组件props:{...},//optional//第二个参数是上下文,没有thisrender:function(createElement,context){//...}})6.子组件划分先看一个例子
{{someThing()}}}
上面代码中,每次父组件传递的数字发生变化,每次都会重新渲染,重新执行someThing这个耗时任务。所以,如果优化的话,一种是使用计算属性,因为计算属性本身就具有缓存计算结果的特性。第二种是Splitintosub-components,因为Vue的更新是在组件粒度上的,虽然第一次数据变化会引起父组件的重新渲染,但是子组件不会重新渲染,因为有里面没有变化,耗时的任务自然不会重新执行,所以性能更好,优化后的代码如下
七.变量本地化简单来说就是保存会被多次引用的变量,因为每次访问this.xx,因为是响应式对象,每次都会触发getter,然后执行依赖收集的相关代码。如果你使用的变量越多,性能就会越差。从需求上来说,一个函数中对一个变量做一次依赖收集就可以了,但是很多人习惯性的写一大堆这个。做事会导致性能问题,比如下面这个例子
{{result}} 八.第三方插件根据需要引入Element-UI等第三方组件库可以按需导入,避免体积过大,尤其是项目不大的时候,不需要完全导入组件library//main.jsimportElement3from"plugins/element3";Vue.use(Element3)//element3.js//完成引入importelement3from"element3";import"element3/lib/theme-chalk/index.css";//导入按需//import"element3/lib/theme-chalk/button.css";//...//import{//ElButton,//ElRow,//ElCol,//ElMain,//.....//}来自"element3";exportdefaultfunction(app){//完全导入app.use(element3)//按需导入//app.use(ElButton);}9.路由懒加载我们知道Vue是单页应用,所以如果懒没有使用loading,会导致进入首页时加载的内容过多,时间过长会出现长白屏,不利于用户体验,SEO也不友好,所以可以使用懒加载来划分页面,在需要的时候只加载对应的页面,分担首页的加载压力,减少首页的加载时间,不用路由懒加载:importHomefrom'@/components/Home'constrouter=newVueRouter({routes:[{path:'/home',component:Home}]})使用路由延迟加载:construuter=newVueRouter({routes:[{path:'/home',component:()=>import('@/components/Home')},{path:'/login',component:require('@/components/Home').default}]})会在进入这个路由的时候去对应的组件,然后运行导入编译和load组件,可以理解为Promise的resolve机制import:Es6语法规范,编译时调用,解构过程,不支持变量函数等require:AMD规范,运行时调用,是一个赋值过程,支持变量计算函数等,前端模块化请看我的另一篇文章前端模块化规范详解总结10.keep-alive缓存页面例如在表单输入页面进入下一步后,然后返??回上一步到表单页面,表单输入的内容要保留,比如在列表页>详情页>列表页,这样来回跳转场景等。我们可以使用内置的-incomponent