干货概览
说到页面性能优化,我们常常想到 首次加载、交互响应和渲染帧率 等页面性能指标。为了给用户流畅的使用体验,我们常常针对这些指标进行优化。接下来,我们以 AIOps 团队智慧机场项目为例,介绍我们如何将首次加载时间为 4000ms 的页面优化至 1350ms 的,文章所介绍的加载优化方法具有一定参考作用,希望能对大家有所帮助。
项目简介
智慧机场项目是一个根据实时航班,对机场机位资源进行动态分配的智能系统。其主要目的是将航班尽量停靠在廊桥机位,增加廊桥机位使用率,减少旅客登机、下飞机时间,同时避免航班因延误等因素对机位的冲突使用,机位的分配情况-甘特图页面如图 1 所示:
图 1 智慧机场甘特图
图中区域 1 表示不同的机位和机位类型,用户可以上下滑动或者通过筛选获得不同机位的信息;区域 2 为时间轴;用户可以滑动时间轴,选择不同的时间段,同时也可以进行缩放操作,来扩大或减小查询范围;区域 3 为内容区,展示不同机位在对应时间段内的航班信息,每一个航班使用条状图展示,条状图颜色表示航班状态,我们分别用几种颜色表示飞机到达、起飞、冲突、返航等属性。整个页面展示与用户交互过程中,甘特图需要根据用户的筛选和操作实时的从后端多个接口中加载数据并进行渲染展示。
该页面与大多数大数据展示页面遇到的性能问题一致,一个是请求的接口多带来请求等待性能下降,另一个是展示的元素多带来的渲染性能下降。在第一版甘特图中,页面的平均加载时间长达 4000ms,下面我们通过通用方案和自定义方案两方面来看一看,我们是如何将加载速度降低到 1350ms 的。
通用优化方案
首先,我们对网页的整个渲染流程来分析,哪些因素会影响网页的加载速度,以及每个阶段对应的常见解决方案分别是什么。
我们可以将网页加载大致分为三个阶段,分别为请求阶段,资源处理阶段,以及页面渲染阶段。甘特图在其中请求耗时约 1600ms,资源处理耗时约 2200ms,页面渲染耗时约 200ms;
请求阶段 主要是资源、数据请求,网络状况及数据量对该部分影响较大,主要优化手段为 优化网络和对数据压缩。在请求阶段,我们通过请求数据压缩的手段,将耗时由 1600ms 减少到 1000ms;
资源解析阶段 主要是对请求下来的资源和数据进行处理,数据规模及处理方式对该部分影响较大,主要优化手段减少数据处理耗时;在资源解析阶段,我们通过 降低处理数据操作复杂度,将耗时由 2200ms 减少到了 2100ms。
渲染阶段 主要是将处理后的数据渲染在页面上,频繁的重绘和重排对该部分影响较大,主要优化手段是 减少重绘和重排。在此阶段我们未做优化。
在甘特图中,我们通过上述通用手段,将总耗时由 4000ms 减少到 3300ms,但是加载速度仍然较慢。所以我们又在数据请求阶段、资源处理阶段的组件初始化及可视化视图渲染计算三个方向进行优化,通过对这三个方向进行优化,我们将耗时由 3300ms 减少到了 1350ms,下面我们将详细对这三方面的优化做介绍。
自定义优化方式
为了进一步降低加载时间,我们利用性能分析工具对网页加载进行进一步分析,发现页面加载过程中,数据请求、组件初始化及渲染计算过程耗时比较长。我们分别对三个过程进行优化:
数据请求部分使用并行请求+请求时执行页面逻辑的方式进行加载速度优化,对于 数据请求多、页面处理业务复杂 的类似页面可以参考此类方法;
组件初始化部分使用延后绑定比较大的数据进行加载速度优化,对于页面 需要监听比较大的双向绑定数据 等类似场景可以参考此方法;
渲染计算部分使用尽量减少图形绘制来提升渲染计算速度,对于使用 ECharts 绘制比较复杂的自定义图形 的页面可以参考此方式;
接下来,我们将详细解说加载速度优化的具体方案。
1 数据请求优化
在智慧机场项目中,页面渲染需要请求用户信息、自定义展示配置等信息和数据,因此请求较多,前端采用串行请求的方式会消耗比较长的时间,因此这里采用 并行发送请求 的方式进行数据请求,如下:
图 2 async 第三方库并发发送请求
第一版甘特图页面渲染需要发送 3 个请求,在增加配置后,请求数增加到 9 个。通过并行请求的方式,页面在发送 3 个请求时,耗时 1000ms,增加到 9 个请求后,串行耗时为 3400ms,通过并发请求的方式,9 个请求耗时降低到 440ms。
但在使用 async 第三方库请求的过程中,CPU 只能处于等待状态。为了充分的利用 CPU,我们采用 ECMAScript 6 标准的 async 函数来对此进行改造。
有别于 async 第三方库使用回调函数的形式做串行处理,ES6 使用 await 关键字等待异步函数返回 Promise 对象做串行处理。首先我们基于 ES6 代码改写 async 第三方库实现:
图 3 async 函数异步使用 await 关键字
然后,我们可以在发送请求时,先不使用 await 关键字,仅保存发送请求的 Promise 对象,在异步请求后端接口过程中,首先进行页面初始化的渲染操作,然后再将异步请求的返回结果进行渲染处理,实现如下:
图 4 改进后利用异步请求等待时间做初始化处理
通过这样的改造,我们在并发请求多个数据的同时,利用请求的间隙,完成绘制初始化、默认配置计算、时间初始化等工作。充分利用 CPU 资源,进一步减少 js 执行耗时 340ms。
通过以上优化,整个加载过程累积减少耗时 900ms,页面加载时间由 3300ms 降至 2400ms 左右。
2 组件初始化优化
智慧机场项目是采用 NoahV(运维前端展现层框架,详情戳这里)开发的,该框架基于 Vue 实现,并采用组件化的思路进行页面元素构建。同时,甘特图的绘制是通过 ECharts 进行绘制的。
在甘特图界面中,用户需要实时调整时间段,获得对应时间段的航班分配情况,故在用户移动时间轴的时候,会根据选择的时间不断更新航班的分配情况,从后端获得对应时间段的航班数据,然后将请求到的数据传入页面组件。
基于 Vue 的双向数据绑定的特征,当数据发生变化的时候,Vue 会构建监听对象去监听数据,再用 ECharts 重绘甘特图。如下是组件监听数据的工作流程。
图 5 组件数据监听工作流程
从图 5 看,当数据传入的时候,为了数据和页面双向绑定,需要构造监听对象,构造监听对象所消耗的时间是根据数据复杂程度决定的。数据越复杂,构造监听对象所消耗的时间越多。
为了加快页面加载速度,我们在首次加载数据时直接渲染图形,减少构建监听对象耗时。在渲染页面完毕后,延迟构造监听对象。流程如图 6:
图 6 改造组件数据工作流程
基于这样的流程优化,航班、机位、待分区航班和待分区机位数据在渲染视图前减少监听对象的构建,耗时相应的分别平均减少约 230ms、210ms、167ms 和 151ms,累积减少耗时约 800ms。页面加载耗时由 2400ms 降低至 1600ms。
3 渲染计算优化
前面我们介绍了页面渲染时减少构建监听对象的过程加快页面渲染时间,接下来我们对可视化渲染视图部分进行进一步分析。
可视化视图渲染耗时随数据量的增加而增大,我们对视图渲染流程做进一步的分析,看哪些流程受到数据量影响较大,渲染视图计算可分为 6 个过程,如图 7:
图 7 渲染计算流程
针对上述流程,我们分别设置不同数据量(表一第一列)及单个甘特条包含不同图形数目(表一第二列),然后通过分析工具查看各个阶段的耗时情况,具体如表 1:
表 1 数据量及每条数据图形对渲染计算各阶段影响
通过表 1,我们可以分析得出,数据量及每条数据所含图形数目对于阶段 1、4、5、6(配置转换、图层刷新、图层渲染和图层合并)没有明显影响。对于阶段 2(图层初始化),在只有一个图形和一条数据时,耗时较短,其他情况耗时相差不大;而对于阶段 3(图形绘制计算阶段),可以明显看出,单条数据所包含图形越多,计算时间越长(表 1 第五列)。因此我们在这里选择减少绘制图形数目(类似减少页面 DOM 节点)来减少渲染计算的耗时。首先,我们对甘特条完整图形进行拆解,如图 8 左侧甘特条拆解所示:
图 8 甘特条图形拆分
由图 8 所示,A 表示发布状态、B 的颜色表示进港航班状态、C 的颜色表示出港航班状态,D 表示播报状态,整个条状图使用 4 个图形绘制。
为了减少绘制图形,我们将这 4 个图形合并为一个图形。首先,我们将 A、D 两个图形分别和 B、C 进行合并,这里采用设置矩形顶角半径的方法来绘制弧度,实现如图 9:
图 9 利用顶角弧度替代弧形 A、D
然后,我们利用分段颜色样式将 B、C 两部分合并,实现如图 10:
图 10 利用分段颜色合并 B、C
这样,我们分别通过矩形顶角弧度设置和分段颜色设置,将 A、B、C、D 四个图形合并成了一个,如图 8 中 X;
三个外框线 E 表示锁定状态、F 表示分割状态、G 表示预测状态,我们将三个框线图形合并为一个,颜色样式同样使用上述分段颜色控制,合并后如图 8 中 Y。
这样,我们就将一个条形图的 7 个图形减少为 2 个。如图 8 中右侧图。
通过合并图形元素,平均每条数据渲染计算的时间减少了 2.5ms,页面平均展示 100 条数据,累积减少耗时约 250ms。页面加载耗时由 1600ms 降至 1350ms 左右。
总结
对于智慧机场项目,我们分别通过 通用解决方案、数据优化、组件初始化优化及渲染计算优化,分别降低页面加载耗时 700ms、900ms、800ms、250ms,累积约 2650ms。页面加载耗时由 4000ms 降低到 1350ms,耗时降低 66%。有效的减少了页面渲染的时间,优化了系统的响应速度,提升了用户体验。整体上,性能优化首先是通过性能分析工具来找到性能瓶颈,再针对每项进行优化。大致会从数据请求,资源解析,数据渲染方向做优化,然后再结合选型框架的特征,进行更细粒度的优化。
作者介绍:
张海超 百度高级前端研发工程师
负责百度智能运维产品(Noah)、智慧机场等前端研发工作,对前端性能优化有广泛的实战经验。
本文转载自公众号 AIOps 智能运维(ID:AI_Ops)。
原文链接:
活动推荐:
2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。
评论 1 条评论