Vue2常见优化手段
Vue2常见优化手段
决明永远不要过早优化,要做到因地制宜,见招拆招。
Vue 应用运行时性能优化措施
1. 使用 key
对于通过循环生成了列表,应该给每个列表项一个稳定且唯一的 key,这有利于在列表变动时,尽量少的删除、新增、改动元素。
2. 使用冻结对象
冻结的对象不会被响应化。有的时候没有必要将数据变成响应式的数据,因为在数据的响应化的过程中需要递归遍历数据,需要耗时。
Object.freeze(this.data) |
如果不希望数据被
Observer
,其实可以在created
的生命周期中把数据挂在到 this 上,并不一定都在 data、props 或者是 computed 中定义。另外,这部分数据也是可以被修改的,只是他们的变化不会触发组件重新渲染,因为我们也并不希望,这样比用 Object.freeze 更加灵活。
3. 使用函数式组件
参见 函数式组件
使用函数式组件,在 js 执行时间以及渲染时间上稍有减少,但是差别不大,同时在内存占用(消耗)方面会比普通组件占用少,这是因为使用函数式组件不会在 vue 的组件树中生成该组件,不会为函数组件创建实例,只是纯渲染。对于普通组件,vue 内部会通过 new VueComponent()对每一个组件创建新的组件实例
函数式组件无状态 (没有响应式数据),也没有实例 (没有 this 上下文)
4. 使用计算属性
如果模板中某个数据会使用多次,并且该数据是通过计算得到的,使用计算属性以缓存它们
5. 非实时绑定的表单项
当使用v-model
绑定一个表单项时,当用户改变表单项的状态时,也会随之改变数据,从而导致 vue
发生重渲染(rerender
),这会带来一些性能的开销。
特别是当用户改变表单项时,页面有一些动画正在进行中,由于 JS 执行线程和浏览器渲染线程是互斥的,最终会导致动画出现卡顿。
我们可以通过使用 lazy
或不使用 v-model
的方式解决该问题,但要注意,这样可能会导致在某一个时间段内数据和表单项的值是不一致的。
6. 保持对象引用稳定
在绝大部分情况下,vue
触发 rerender
的时机是其依赖的数据发生变化,若数据没有发生变化,哪怕给数据重新赋值了,vue
也是不会做出任何处理的,下面是 vue
判断数据没有变化的源码
export function hasChanged(x:unknown,y:unknown):boolean { |
因此,如果需要,只要能保证组件的依赖数据不发生变化,组件就不会重新渲染。
对于原始数据类型,保持其值不变即可
对于对象类型,保持其引用不变即可
从另一方面来说,由于可以通过保持属性引用稳定来避免子组件的重渲染,那么我们应该细分组件来尽量避免多余的渲染
7. 使用 v-show 替代 v-if
对于频繁切换显示状态的元素,使用 v-show 可以保证虚拟 dom 树的稳定,避免频繁的新增和删除元素,特别是对于那些内部包含大量 dom 元素的节点,这一点极其重要
关键字:频繁切换显示状态、内部包含大量 dom 元素
8. 使用延迟装载(defer)
首页白屏时间主要受到两个因素的影响:
打包体积过大
巨型包需要消耗大量的传输时间,导致 JS 传输完成前页面只有一个<div>
,没有可显示的内容需要立即渲染的内容太多
JS 传输完成后,浏览器开始执行 JS 构造页面。
但可能一开始要渲染的组件太多,不仅 JS 执行的时间很长,而且执行完后浏览器要渲染的元素过多,从而导致页面白屏
一个可行的办法就是延迟装载组件,让组件按照指定的先后顺序依次一个一个渲染出来
延迟装载是一个思路,本质是利用
requestAnimationFrame
事件分批渲染内容,它的具体实现多种多样。
9. 使用 keep-alive
keep-alive 组件是 vue 的内置组件,用于缓存内部组件实例。被包裹的组件在切换的时候不会被销毁,直接使用缓存中的实例,好处是避免创建组件带来的开销、而且可以保留组件的状态,但是会因此占用更多的内存。
属性
- include 哪些组件缓存
- exclude 哪些组件不缓存
- max 最大缓存数,超出 vue 会自动移除最久没有使用的组件缓存
// 写法1 |
关于 max 属性,vue 是这么判断的
cacheVNode() { |
特有的生命周期
- activated 组件激活时调用,第一次调用是在 mounted 之后调用
- deactivated 组件失活时调用
常见的应用场景
后台管理系统的选项卡,当菜单添加到选项卡时,就对选项卡中的菜单进行缓存,提高用户的使用体验。
原理
keep-alive 在内部维护一个 keys 数组和一个缓存对象 cache
created() { |
keys 数组记录缓存组件的 key 值,如果组件没有,就会为组件自动生成一个唯一的 key 值
const { cache, keys } = this |
cache 以 key 值为键,以 vnode 为值,用于缓存组件对应的虚拟 DOM
keys:[1,2,3] |
大致流程:
render() { |
10.长列表优化
如果你的应用存在非常长或者无限滚动的列表,那么采用 窗口化 的技术来优化性能,只需要渲染少部分区域的内容,减少重新渲染组件和创建 dom 节点的时间。vue-virtual-scroll-list
和 vue-virtual-scroller
都是解决这类问题的开源项目。你也可以参考 Google 工程师的文章 Complexities of an Infinite Scroller
来尝试自己实现一个虚拟的滚动列表来优化性能,主要使用到的技术是 DOM 回收、墓碑元素和滚动锚定。
Vue 应用加载性能优化措施
1.利用服务端渲染(SSR)和预渲染(Prerender)来优化加载性能
在一个单页应用中,往往只有一个 html 文件,然后根据访问的 url 来匹配对应的路由脚本,动态地渲染页面内容。单页应用比较大的问题是首屏可见时间过长。
单页面应用显示一个页面会发送多次请求,第一次拿到 html 资源,然后通过请求再去拿数据,再将数据渲染到页面上。而且由于现在微服务架构的存在,还有可能发出多次数据请求才能将网页渲染出来,每次数据请求都会产生 RTT(往返时延),会导致加载页面的时间拖的很长。
2.组件懒加载
在超长应用内容的场景中,通过组件懒加载方案可以优化初始渲染的运行性能,其实,这对于优化应用的加载性能也很有帮助。
组件粒度的懒加载结合异步组件和 webpack 代码分片,可以保证按需加载组件,以及组件依赖的资源、接口请求等,比起通常单纯的对图片进行懒加载,更进一步的做到了按需加载资源。
使用组件懒加载方案对于超长内容的应用初始化渲染很有帮助,可以减少大量必要的资源请求,缩短渲染关键路径。