likes
comments
collection
share

Vue项目-首页性能优化实战

作者站长头像
站长
· 阅读数 32

前端性能优化实战

性能问题作为web项目的瓶颈,深受各位前端开发者的诟病。 爱它高性能的优化体验,恨它难以分析定位。

本文介绍实际项目中的性能问题分析过程及优化结果可供有类似问题的读者参考

一、背景

1.1 项目背景介绍

vue2+element-Ui+webpack4搭建的单页面web应用。 页面路由数量3000+、整体体量300M+、前后30+前端同事参与代码开发 标准的复杂管理系统

1.2 问题背景

进入系统首页,打开菜单列表,任意点击菜单列表菜单,点击进入子菜单,跳转对应模块页面。 首次点击菜单大约等待17秒后跳转进入对应菜单页面。 点击菜单页面跳转出现卡顿,浏览器进入假死状态,此时点击页面无任何响应。

二、过程分析

2.1 疑问点

影响路由跳转的因素思前想后,只有这两个可能原因:

  • 项目体量大、页面路由过多导致的路由跳转卡顿?

  • 代码原因导致的浏览器假死呢?

页面路由过多的原因吗? 项目路由采用的是路由懒加载模式

export default new Router([
    routes:[
    	{
    	    path:'/Login',
    	    name:'Login',
    	    component:resolve => require(['@/components/Login'],resolve)
    	}
    	...	
    ]
])

通过Webpack编译打包后,会把每个路由组件的代码分割成一一个js文件,初始化时不会加载这些js文件,只当激活路由组件才会去加载对应的js文件。

笔者异步组件这篇文章记录过异步组件的导入过程,需要查看的读者可自行阅读。

想明白这个原因后,果断把根本原因放在代码层面上。 项目开发到中后期要去整体通过代码逻辑去分析性能问题,不可谓不难。 除非全周期参与开发,整体架构代码非常熟悉,这样的人或许存在吧... 就算是存在 也恐怕是“不识庐山真面目,只缘身在此山中!”

我们借助chrome提供的performance性能分析面板工具,记录分析过程并分析。

2.2 分析过程

从点击菜单跳转到菜单跳转结束录制性能分析报告图如下: Vue项目-首页性能优化实战

a)标记S区域即模拟用户正常点击菜单直到跳转到对应模块页面整个过程25.27秒,Scripting块-js执行的时间最长18541ms,idle块-空闲时间6168ms,其他块在可接受时间范围内,不参与本次分析。  

b)标记P区域即跳转期间内存统计折线图。内存的起伏点发生在2000ms处-点击跳转后,2000ms以后JS Heap堆内存、Nodes节点元素消耗内存、Listeners 监听事件消耗内存都持续上升,达到最高点  

c)标记T1-T5区域为主线程任务调用栈调用过程。T1任务明显是鼠标移动事件过程;T2任务是点击菜单后菜单页面的调用栈过程;T3任务可看出是点击菜单的调用栈过程;T4任务是跳转的页面生命周期执行调用栈过程;T5任务是页面异步请求回来后页面重绘调用过程。  

d)N1-N2区域为网络调用过程。N1是跳转路由时在路由守卫处做的菜单权限检验,请求的异步接口判断当前跳转菜单是否属于当前登录人;N2是要跳转的页面异步请求页面数据的过程;N1位于T3和T4之间,N2位于T4和T5之间  

e)F1-F5区域为帧速率告警,一般FPS在大于等于60时,页面会很流畅,低于60时页面就会卡顿;F1-F5都出现了不同程度的告警,对应于页面的长时间的卡顿。

在收集分析以上各项指标后,以主线程执行火焰图来看,整个过程主要的时间是消耗在T4-跳转的页面生命周期执行调用栈过程,放大T4阶段调用栈火焰图: Vue项目-首页性能优化实战 由于调用栈非常之深,这里只截取了最上部分示意图,这里直接滑动到最底部,这里以最长的调用栈来说明如下图所示: Vue项目-首页性能优化实战 栈底都是执行created、initGlobal、anonymous2次;绿色区域都是框架代码,其他颜色就是我们要关注的区域,分别点击这四个区域在S面板下即可看到详细信息,如下图: Vue项目-首页性能优化实战 Vue项目-首页性能优化实战 Vue项目-首页性能优化实战 Vue项目-首页性能优化实战

再次点击P面板的代码链接就能看到真实代码。

通过以上分析得出优化思路如下: 1、找到项目中 created、initGlobal、anonymous-session.Js的调用过程 2、找出持续多次调用此类方法的原因 3、优化涉及代码

2.3 解决方案

通过分析代码发现在系统主入口中有添加过一个mixins-全局混入,火焰图中T4、T2过长的调用栈栈顶执行的函数都是mixins的生命周期函数。 查询vue官网-全局混入资料如下图:

Vue项目-首页性能优化实战

我们在全局混入的生命周期created中打印关键字,

Vue项目-首页性能优化实战 接着观察控制台打印,

Vue项目-首页性能优化实战

打印多次输出,再次查询资料,全局混入每一个vue实例在创建时都会执行该函数,这里的每一个vue实例,可以理解为一个个vnode实例,不同类型的vnode实例各自表示不同类型的DOM元素,vnode实例化是对应vue.js中存在的VNode类。 这里可以理解为一个真实的DOM节点,这里我们不深入介绍。 问题分析到此,如果我们替换全局混入为局部混入是不是就能解决本次性能上出现的问题。 说干就干,实际修改代码后模拟用户点击打开菜单列表点击菜单跳转录制分析图如下: Vue项目-首页性能优化实战 再次分析上图:

a)S区域整个过程6736ms,idle-线程空闲时间最长5212ms,Scripting-js执行时间947ms,已经达到可接受时间范围

b)P区域出现 两个峰值,峰值1出现在2000ms左右查看缩略图是打开菜单列表过程;峰值2出现在4500ms左右,查看缩略图是点击菜单列表跳转到对应页面;时间点后移JS HEAD-堆内存下降并趋于平缓,Documents元素下降并趋于平缓标志页面渲染完成;Nodes-节点、Listenters-事件监听正常在执行

c)T区域出现T1、T2两个任务,T1文字可见是鼠标移动事件耗时448.12ms;T2是跳转页面的初始化事件耗时326.84ms;  

d)N区域网络请求过程; N1是跳转路由时在路由守卫处做的菜单权限检验,请求的异步接口判断当前跳转菜单是否属于当前登录人;N2是要跳转的页面异步请求页面数据的过程;N1位于T3和T4之间,N2位于T4和T5之间; 对应单线程js执行原理。

e)F区域帧速率记录区 F1对应页面的鼠标移动事件,尾部出现了红块-毫秒级别的卡顿;F2对应跳转页面的初始化事件,在F2的尾部出现了红块-毫秒级别的卡顿

再查看栈底火焰放大图如下图: Vue项目-首页性能优化实战 此时栈底的事件基本全是框架调用过程,图中两个较为明显粉色的微任务也是在最大3.22ms内执行完毕,如下图

Vue项目-首页性能优化实战 Vue项目-首页性能优化实战

三、优化结果比较

  • 优化前:
模拟用户点击菜单跳转整体消耗25.27s;scripting-js执行18541ms;idle-空闲事件6168ms;卡顿事件 15.98s
  • 优化后:
模拟用户点击菜单跳转整体消耗6878ms;scripting-js执行947ms;idle-空闲时间 5354ms;卡顿时间326.84ms

全局混入的全局变量导致系统卡顿,替换全局混入为局部混入即可。 分析问题解决问题过程是兴奋地,改代码花了8+小时,修改了720+文件,整个过程都是晕晕乎乎,不停的告诉自己,快完了、要结束了... 值得欣慰的是整个测试验证过程相对很顺利!鼓掌鼓掌鼓掌

四、总结

性能问题作为web项目开发的重点,是可以提前预防的。 雅虎的35条军规就是行业标准,网上也有很多解析雅虎军规的文章可供参考。 如果可以的话,尽量不要把性能优化的事,放在项目开发的中后期做,中后期项目架构、技术方案基本已经成熟,如果此时因为性能优化的问题,需要调整技术方案的话,那就得不偿失了。 本文主要记录使用chrome浏览器提供的performance性能分析面板分析问题并解决,分析过程如正文,可供有相同问题的读者参考。