前端加载优化实战

二叶草 2020年3月10日20:46:42前端框架评论阅读模式

说到网页页面特性提升,人们经常想起初次载入、互动回应和3D渲染帧数等网页页面性能参数。以便给客户顺畅的应用感受,人们经常对于这种指标值开展提升。接下去,人们以AIOps精英团队聪慧飞机场新项目为例,介绍我们如何将首次加载时间为4000ms的页面优化至1350ms的,文章所介绍的加载优化方法具有一定参考作用,希望能对大家有所帮助。

项目简介

智慧机场项目是一个根据实时航班,对机场机位资源进行动态分配的智能系统。其主要目的是将航班尽量停靠在廊桥机位,增加廊桥机位使用率,减少旅客登机、下飞机时间,同时避免航班因延误等因素对机位的冲突使用,机位的分配情况-甘特图页面如图1所示:

前端加载优化实战

图1  智慧机场甘特图

图中区域1表示不同的机位和机位类型,用户可以上下滑动或者通过筛选获得不同机位的信息;区域2为时间轴;用户可以滑动时间轴,选择不同的时间段,同时也可以进行缩放操作,来扩大或减小查询范围;区域3为内容区,展示不同机位在对应时间段内的航班信息,每一个航班使用条状图展示,条状图颜色表示航班状态,我们分别用几种颜色表示飞机到达、起飞、冲突、返航等属性。整个页面展示与用户交互过程中,甘特图需要根据用户的筛选和操作实时的从后端多个接口中加载数据并进行渲染展示。

该页面与大多数大数据展示页面遇到的性能问题一致,一个是请求的接口多带来请求等待性能下降,另一个是展示的元素多带来的渲染性能下降。在第一版甘特图中,页面的平均加载时间长达4000ms,下面我们通过通用方案和自定义方案两方面来看一看,我们是如何将加载速度降低到1350ms的。

通用优化方案

首先,我们对网页的整个渲染流程来分析,哪些因素会影响网页的加载速度,以及每个阶段对应的常见解决方案分别是什么。

我们可以将网页加载大致分为三个阶段,分别为请求阶段,资源处理阶段,以及页面渲染阶段。甘特图在其中请求耗时约1600ms,资源处理耗时约2200ms,页面渲染耗时约200ms;

  1. 请求阶段主要是资源、数据请求,网络状况及数据量对该部分影响较大,主要优化手段为优化网络和对数据压缩。在请求阶段,我们通过请求数据压缩的手段,将耗时由1600ms减少到1000ms;
  2. 资源解析阶段主要是对请求下来的资源和数据进行处理,数据规模及处理方式对该部分影响较大,主要优化手段减少数据处理耗时;在资源解析阶段,我们通过降低处理数据操作复杂度,将耗时由2200ms减少到了2100ms。
  3. 渲染阶段主要是将处理后的数据渲染在页面上,频繁的重绘和重排对该部分影响较大,主要优化手段是减少重绘和重排。在此阶段我们未做优化。

在甘特图中,我们通过上述通用手段,将总耗时由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左右。

 

本文来源于:前端加载优化实战-变化吧门户
特别声明:以上文章内容仅代表作者本人观点,不代表变化吧门户观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 加入Q群
  • QQ扫一扫
  • weinxin
二叶草
Go语言接口规则 前端框架

Go语言接口规则

Go语言接口规则 接口是一个或多个方法签名的集合。任何类型的方法集中只要拥有该接口对应的全部方法签名。就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。对应方法,是指有相同名称、参数...
Go语言中处理 HTTP 服务器 前端框架

Go语言中处理 HTTP 服务器

1 概述 包 net/http 提供了HTTP服务器端和客户端的实现。本文说明关于服务器端的部分。 快速开始: package main import (   "log"   "net/http" )...

发表评论