【案例分享】腾讯游戏说:从 Web 性能评估探寻前端优化策略

2022-03-18 13:10:14 浏览数 (2)

刘馨忆

腾讯 IEG 公共数据平台部前端开发工程师,硕士毕业于英国曼彻斯特大学。主要负责内容生态相关toB 业务系统的开发,对内容审核链路、数据可视化看板有丰富的开发经验。

前言

作为一名前端开发者,想必你一定知道前端技术的迅猛发展。每过一段时间都会有热火朝天的新技术或者新开发方式,前端开发者也经常嘲讽“求不要更新了,学不动了”、“一入前端深似海”等。随着前端技术和业务的发展,我们也难免会遇到前端项目重构的问题,那究竟该如何评估目前前端技术框架的质量,众多性能指标我们该如何衡量呢?

本文将介绍新一代 Web 页面性能评估方案。逐渐梳理出一种较为合理的新旧系统页面性能评估对比方案,在不适用的场景下如何添加自定义测速,以及在得到指标数据后如何尽可能的做一些性能优化。

为什么需要对页面性能做出量化评估

游戏说管理端(腾讯内部智能化游戏内容增长平台)系统庞大内容繁多、并且多年来基于业务需求不断堆叠功能定制代码,现下已经很难继续进行新功能开发,因而在2020年下至2021年初开始逐步对旧版游戏说管理端的页面进行重构。

在完成3个左右页面重构之后,除去在用户体验交互上一些主观的感受之外,如何基于完全不同的前端技术框架来评估 Web 页面的性质量好坏是复盘阶段的关键,有效地收集性能数据也可以对之后的研发方向提供正确的引导。

目前,对网页的性能评估可以从很多维度来进行。本文准备梳理一些较为关键的性能指标来明确我们之后应该关注的一些方向,以及在数据收集阶段做了哪些努力来进行性能和数据的优化。

从输入域名到页面展现

浏览器做了什么?

从开发&运维角度方面来看,总体来说分为以下几个过程:

  • DNS 解析:将域名解析成 IP 地址。
  • TCP 连接:TCP 三次握手。
  • 发送 HTTP 请求。
  • 服务器处理请求并返回 HTTP 报文。
  • 浏览器解析渲染页面。
  • 断开连接:TCP 四次挥手。

在从 URL 输入到页面展现到底发生什么?我们关注的是在浏览器完成解析渲染页面这一步做了哪些工作,从前端的角度的来讲大致有页面资源加载(包含样式文件、JS 文件、图片等)以及拿到内容后的渲染。以 chrome 的 webkit 内核为例:

[点击查看大图]

浏览器内核拿到内容后,大致有以下几个渲染步骤:

  • 解析 HTML,构建 DOM 树。
  • 解析 CSS,生成 CSS 规则树。
  • 合并 DOM 树和 CDD 规则树,生成 render 树。
  • 计算各个元素的位置尺寸等信息,布局 render 树。
  • 绘制 render 树。

了解页面渲染机制可以更好地帮助我们理解页面指标的含义,接下来我们来看页面的性能可以从哪些维度评估。

如何客观评估用户体验质量?

优化用户体验一直都是项目开发过程中的重要环节,用户体验的好坏可能直接关系到项目成败。在不同的情境中对用户体验的评估维度可能会是不同的,根据谷歌提供的 Chrome DevTools 各个网站共享一组通用的指标 Core Web Vitals,2020年最新一代的标准中包含加载体验、交互性和视觉稳定性。接下来我们先来了解下三个可度量的指标:

[点击查看大图]

1. Largest Contentful Paint (LCP)

最大内容渲染时间指标。

由于该时间会随着页面内容的实际渲染过程而变化,因此是一个非常重要的指标,它意味着标准报告视窗内的最大内容元素的渲染时间,一般应该在 2.5s 以内完成。为了保持该指标的简单性,它现在只考虑几种元素:

  • <img> 元素
  • <image> 元素内的 <svg> 元素
  • <video> 元素
  • CSS 中通过 url( ) 加载背景图片的元素
  • 包含文本节点或其他内联文本元素子级的块级元素

最大内容的渲染是指当前视窗内可见的渲染面积最大的元素,页面的加载过程是线性的,元素是一个一个逐步渲染到页面上的,而不是一瞬间全部渲染上去,所以这个渲染面积最大的元素可能随时在发生变化

[点击查看大图]

2. First Input Delay (FID)

记录用户和页面进行首次交互操作所花费的时间。

衡量可交互性指标,为了提供良好的用户体验,页面的 FID 应当小于 100毫秒。

[点击查看大图]

如上图所示,FID 发生在 FCP 之后,到 TTL(Time To Live)的这段时间。浏览器接收到用户输入操作时(<input><select><a>),主线程正在忙于执行一个耗时比较长的任务,只有当这个任务执行完成后(任务执行为线性的),浏览器才能响应用户的输入操作。它必须等待的时间就是此页面上该用户的 FID 值。

[点击查看大图]

3. Cumulative Layout Shift (CLS)

衡量视觉稳定性指标。

衡量视觉稳定性,为了提供良好的用户体验,页面的 CLS 应保持小于 0.1。

由于异步加载资源或将 DOM 元素动态添加到现有内容上方的页面而发生的页面内容的突然移动,该资源可能是未知尺寸的图片或视频,自带字体的加载、或者是动态调整自身大小的第三方广告或小部件。

改善方式:

  • 给未知的元素限定尺寸。
  • 给动态插入的广告位预留空间。
  • 预加载自定义的字体文件、先使用默认字体,等自定义字体加载完成后再进行替换。

如何客观评估重构项目的性能指标?

了解了上述谷歌提出的三个页面性能指标后。我们在众多的前端性能监控平台中重重筛选。最后选择了接入腾讯云前端性能监控(RUM),RUM 支持从不同维度对前端页面性能进行分析统计,能给我们评估重构项目的性能指标提供很大的帮助。RUM 提供的页面性能监测功能,同时还支持谷歌提出的 LCP、FID 、CLS 三大指标和下列页面性能指标数据:

1. DNS 查询:

domainLookupEnd -domainLookupStart;

2. TCP 连接:

connectEnd - connectStart; 3. SSL 建连:

requestStart - secureConnectionStart; 4. 请求响应:

responseStart - requestStart; 5. 内容传输:

responseEnd - responseStart; 6. DOM解析:

domInteractive - domLoading; 7. 资源加载:

loadEventStart - domInteractive; 8. 首屏耗时:监听页面打开5s内的 首屏 DOM 变化,并认为 DOM 变化数量最多的那一刻为首屏框架渲染完成时间,这期间如果有请求图片,则认为图片是首屏重要的组成部分,默认认为图片加载完成时间为首屏时间,如果没有请求图片,则认为首屏框架时间为首屏时间; 9. 页面完全加载时间:为1-7项数据之和;

[点击查看大图]

目前对游戏说-管理端来说最有意义的指标是首屏时间,因为直接关乎到用户体验,用户点击进来多久能看到完整的前端页面。因此后续的调整和优化都是围绕这个指标来展开的。

但在实际的应用场景中我们发现,不同前端技术框架下所监测到的首屏加载时间的准确性是有可能打折扣的。此时我们在第一阶段(2020-12-02至2020-12-16)收集到的数据表现和实际情况感官上就有显著的区别,使用 Chorme DevTools 提供的  Performance 功能测试了页面性能发现旧版页面的加载从开始请求域名到最终完成列表请求 searchNewListVv 的时间跨度是远多于第一阶段的 1598ms 。

性能面板中收集到的旧版列表页性能指标:

[点击查看大图]

我们分析原因在于旧版管理端采用的 HTML data-* 属性来嵌入自定义数据,在腾讯云前端性能监控(RUM)中监测到有大量 DOM 变化时实际的列表渲染还没有完成,只是先渲染完成了一部分静态页面。因此需要进行自定义打点上报来甄别有效指标。在代码中,我们根据执行顺序找到列表最终渲染完成、Loading 消失的节点加上了自定义上报,得到了相对有效的指标数据。

自定义上报打点如何添加?

保持和- Aegis 一致的时间计算方案,从 Performance Timing 获取页面从开始加载到最终渲染完成所需要的时间。

根据 Performance - Web API 接口给出的计算方式,直接选用 now( ) 函数,然后接入 腾讯云前端性能监控(RUM) 的自定义上报接口。

访问链接了解 Performance - Web API: https://developer.mozilla.org/zh-CN/docs/Web/API/Performance。 Performance.now() 返回一个表示从性能测量时刻开始经过的毫秒数 DOMHighResTimeStamp。

[点击查看大图]

详情请参考腾讯云前端性能监控上报文档:

https://cloud.tencent.com/document/product/1464/58563#reporttime。

围绕性能数据我们做了哪些优化?

经过上述一系列分析,首先,我们在前端优化的角度做了以下优化:

1. 使用 gzip 压缩资源,资源可被压缩至原尺寸的10%~20%。

  • 项目压缩方式改为:gizp 。
  • 修改 nginx 默认配置支持 gzip 格式。

gzip 压缩后控制台显示前后压缩尺寸对比:

性能面板中的 gzip 压缩显示:

[点击查看大图]

2. 设置路由懒加载,减少不必要的依赖文件加载。

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。

路由懒加载指南:

https://router.vuejs.org/zh/guide/advanced/lazy-loading.html

3. 静态资源 CDN 缓存

另外,我们发现在新版页面中页面渲染完成的时间很大程度上依赖于接口请求所需的时间,根据 Chorme DevTools 的 Network 面板所提供的信息,我们对耗时较长的接口和后端同学一起进行了一轮速度优化:

[点击查看大图]

主要做了接口缓存、接口慢请求字段拆分等改进,将之前平均耗时在 4.5s 的 searchNewListVv 接口优化到 900ms 左右,显著缩短了接口请求的耗时。得到了第二期数据表现结果(左为旧,右为新):

接口请求测速结果:

[点击查看大图]

页面渲染测速结果:

[点击查看大图]

此时的性能优化已经初见成效,结果表明重构后的页面首屏渲染时间比旧版提升了27%,但效果还不够显著,我们认为还有继续提升的空间,考虑到管理端接入了几百个业务,几个头部业务都有定制化功能导致不同业务的性能表现不一,在之前我们获取的始终是各业务平均的结果,因此需要对重点业务进行抽离分析,才能得到更加有效的数据对比结果。

所以我们对旧版的自定义上报加上了业务 ID 后缀(18),对新版页面做了正式线的灰度发布(仅收集18业务下的上报数据)。并且再次分析 Performance 性能表现发现可以对某些接口的请求顺序做调整,将非必要条件的后置请求改为并发(Promise.all),下列为请求并发前、后的接口测速结果:

[点击查看大图]

如图,一个列表拉取的请求 search 在请求的 Waterfall 图中红色框的接口是优化之后的状态,优化前是黄色框状态,意味着之前在等待所有前置接口(各种初始化数据集 tag,channel 等)中,耗时最长的一个接口请求完成之后才会执行 search 请求拉取列表数据,再次考虑其中的逻辑之后发现 search 请求在发起时并不需要依赖其他请求的返回结果,而是拿到返回值后的数据处理才需要用到初始化数据集,因此我们合理的将请求发起时间节点提前,在同时拿到列表数据和初始化数据集之后我们就去渲染列表,这样整体上节省了差值等待时间,提高了首屏渲染的速度,获得到第三轮的优化数据结果:

[点击查看大图]

此时在 18业务下的页面性能优化就十分显著了,从旧版的 8588.63ms 到新版的3333.86ms,实现同比缩减61%

小结

页面性能优化的衡量指标有通用的一套标准,但也应该根据实际的需求和关注点因地制宜地进行调整,梳理出我们重点关注的指标。本文通过  腾讯云前端性能监控(RUM)对项目进行定向分析,拆分出不同阶段的具体耗时,再对计划外的耗时做定向处理。这也是我们通过实践,总结出来的一套 Web 项目性能优化可行方案。性能优化可能会是一个漫长的过程并且需要不断的尝试,但是这些微小的差异叠加在一起有可能会对用户体验带来质的飞跃,因此在项目开发完成后,合理有效地进行性能数据分析和性能优化是项目闭环的重要环节,也应当在此做出努力。

腾讯云前端性能监控(RUM)是可用于 Web 和小程序的前端真实体验监控服务,基于腾讯内部多年实践,一行代码、无侵接入,实现页面性能和前端质量的实时可观测。还支持以下前端监控场景,您还可以点击文末 [阅读原文] 了解更多腾讯云前端性能监控信息。 

联系我们

如有如何疑问,欢迎加入云监控技术交流群

前端性能监控相关文档推荐:


关注我们,了解腾讯云监控的最新动态

0 人点赞