查看原文
其他

如何从零开始做性能优化

严选技术 严选技术产品团队 2022-11-14





性能优化作为一个老生常谈的项目,能在网上看到各种优化点,但对于一个新手来说,要着手一个完整的性能优化项目,却不知从何下手。这篇文章将介绍如何从零开始做性能优化,介绍如何将性能优化项目落地、推进、实施,对业务赋能等。


1. 先来一个面试

首先,先来一个面试题:请你介绍下前端性能优化?(不妨在浏览下方内容前,先自我回答下这个问题。

在实际面试他人过程中,问到这个题目时,往往都没得到一个满意的答案,大部分的人上来就是图片懒加载,css 压缩,js 压缩之类的内容,其实没错,但也可以知道对方是没有做过系统性的性能优化的。

2. 文档目录

那么怎么样的才算是系统性的性能优化呢?看完这个文章就知道了。

本文将从以下四个内容进行介绍:

  • 为什么要做?(为什么需要对项目做性能优化,前端性能优化的价值在哪里?)

  • 如何做?(如何做一个完整的性能优化,如何下手?)

  • 最佳实践(网易严选业务中比较有效且特殊的策略分享)

  • 结语(整个内容的回顾)

3. 为什么要做?

在做性能优化这个事项之前,我们得先知道我们做的这个事情是否有价值。

3.1 用户体验金字塔

先来看一个用户体验金字塔,大家觉得对用户体验影响最大的内容是啥?

页面的颜色? 页面的信息?其实都不是,肯定是性能优化相关的内容,因为本篇文章的主题就是性能优化。

从 google i/o 大会上,能看到对用户体验造成最大影响的就是页面的加载时长。这个其实也很好理解,你的页面做得非常精美,但是前置的流程是需要用户能看到这个页面。

3.2 性能优化业务价值

页面加载时长对用户体验有影响,那么对业务数据是否有影响呢?

答案是肯定的,页面加载时长越长,越容易造成用户流失,超过 5s,90% 的用户就会离开。

可以想象一下,你手上的业务如果页面加载时长缩短几百毫秒,甚至更多,是不是对业务也会起到正向的作用呢?

4. 如何做?

既然性能体验优化是非常有价值的,那么我们该如何来做呢?

4.1 意识阶段

在讲具体怎么做之前,先说下性能优化的意识状态。

在正式启动性能优化之前,一般都处于无意识状态,面试中,往往回答的也都是这类答案。在系统化的性能优化中,我们需要优先改变自己的意识状态,进阶到状态 3 和状态 4 中,状态 3、4 需要我们关注指标,关注数据。

强调下,性能优化的首要基础是指标数据

4.2 性能体验提升流程

在意识形态改变以后,性能体验提升流程可以分为以下 4 个内容:

  • 建设度量体系(确定性能衡量指标,建设性能监控平台)

  • 制定目标(度量体系接入&现状数据分析)

  • 性能优化实施(团队组织和项目推进,产出优化策略)

  • 成果验收和复盘

4.2.1 建设度量体系

首先我们来建设衡量页面的度量体系。度量体系分成衡量指标和监控平台。

那用什么指标来衡量这个页面的性能呢?我们说这个页面很快或者很卡,都是基于主观的一个感受,这个是无法量化的。在项目实施中也无法说我对这个页面进行了优化,这个页面变快了,无法量化的数据也无法给你合理的评分。

现在 okr 很流行,很重要的点就是量化,同理,对于页面性能我们也需要一个量化的值来表示页面性能。

4.2.1.1 页面性能衡量指标三个阶段

实际上,页面性能衡量指标经历了 3 个阶段,围绕的都是首屏时间。

  • 第一阶段:自定义打点时期

    页头和首屏 dom 处分别通过 new Date() 打点,方法笨重,精确度不高,数据单一。

  • 第二阶段:W3C标准时期

    后面就进入了第二阶段,W3C 标准时期,通过 performance api 来做计算,但是随着单页的流行,load 时间早于首屏时间,W3C 标准失去了原先的意义。

  • 第三阶段:感官性能优化指标

    到了现阶段,引入了感官性能优化指标。主要分成 FP、FCP、FMP、TTI 等数据指标,其中比较符合首屏时间的就是 FMP 指标,可惜没有直接的系统 api 提供。

    新版本提供了LCP,类似于FMP的时间,但存在兼容性,而对于性能这个事项,慢网络和老设备更是应该关心的点。

    既然没有直接的 api 提供,那么可以大胆地猜想首屏中主要元素的加载完成时间类似的等同于 FMP 时间。

4.2.1.2 捕获FMP原理

成为FMP元素的条件

首屏中,怎么样的元素才可以成为主要元素呢?
看截图,主要是一些体积大,屏幕占比大,多是一些图片,视频,canvas等元素。这些元素加载完成的时间则可以近似的认为 FMP 的时间。

4.2.1.3 FMP算法设计

这样,我们就可以设计一个算法。

  1. 通过监听元素加载

  2. 根据可视区域面积,元素权重等关系,计算元素的得分

  3. 子元素的得分之和父元素得分做比对,取较大值,得到可视区域内得分最高的元素集合。

  4. 过滤分数超过平均分的元素,拿到更小范围的元素集合。

  5. 再对这些元素取最大的加载时间,这个时间则可以用来作为 FMP 的时间。

4.2.1.4 建设性能监控平台

完成了性能优化衡量指标后,就可以借助性能衡量指标来做一个性能监控平台,一个好的监控平台,往往有以下功能:

  • 数据可视化:可以直观地看到各业务的实时数据大盘

  • 慢加载追踪:提供慢页面列表和多维度数据

  • 性能瓶颈定位:可以针对性的查看某个用户访问路径,查看用户各节点的性能瓶颈

  • 性能报警:性能报告和线上报警

性能监控平台也是重要的一块内容,本篇文章主要介绍完整流程,后续再做介绍。

4.2.2 制定目标

完成性能度量体系后,就需要接入性能体系,对业务现状做数据分析,制定行动的目标。

以严选 C 端业务为例,制定了 FMP 1.2s 以内为达标标准,分成了三块业务:活动、用户、商城,根据现状数据和业务场景,制定了对应的目标。

4.2.3 性能优化实施

有了一个量化的目标后,就可以真正地进入到策略实施验证的阶段了。

4.2.3.1 团队组织和整体思路

先理一下思路:

  1. 我们可以基于衡量指标制作一个性能分析工具,专项的分析页面性能瓶颈

  2. 使用常规的性能优化策略,结合严选业务的优化策略

  3. 记录每次性能优化的数据变化

  4. 沉淀有效策略

  5. 在团队各业务中快速落地

思路可能过于理想,真实的落地中会遇到一些问题,根据之前的经验,觉得需要再加一条,建设一支强有力的队伍,来保证性能优化这个事项的落地。

大家对于平台/工具类的内容建设都比较热衷,但对于最终的落地都缺乏一定的执行力,因此采取一定的制度保障项目落地是非常必要的。

4.2.3.2 分析

性能优化的策略很多,如何很好地串联起这些策略点呢?可以先从这个问题开始:

从输入地址到页面显示经历了哪些过程?

简单的可以分为这几个阶段:

  1. 输入 URL 地址

  2. 缓存解析

  3. 域名分析

  4. TCP 连接

  5. 服务器响应

  6. 浏览器渲染

从链路中,我们可以提取这几个关键词:缓存、TCP连接、服务器、响应体、渲染,性能优化将从这些关键词中产出关键策略。

  • 页面链路:缓存

首先是缓存,缓存分为 HTTP 缓存、浏览器缓存、应用缓存、App缓存,对于前端,往往关注在前几个缓存,App 缓存这里介绍下,按需缓存就是之前经常反馈的 HTTP 缓存明明关闭了,为啥我的页面在 App 中还是不生效的罪魁祸首,以及 App 中非常有效的预缓存策略,可有效的提升页面性能。

  • 页面链路:TCP连接(HTTP2.0)

    下一步,TCP 连接,随着页面的复杂度提升,一个页面往往会有上百个请求,请求的头部信息往往都是一致的,头部开销偏大,升级到 HTTP2.0,则可以有效地节省这部分开销。

  • 页面链路:服务器(CDN 服务器)

    完成 TCP 连接后,进入服务器响应,对于服务器我们也有一定的优化点,对于静态资源,可以接入 CDN 服务器,可有效地提升网站的稳定性,大大地缩减资源加载时间。

  • 页面链路:响应体(GZIP)

    服务器返回响应体,响应体的内容未经压缩的话,体积往往比较大,采用 GZIP 压缩,可以大大的缩减文本类的资源体积,而对于图片资源则效果不大。

    因为 GZIP 采用的是 LZ77 和哈夫曼算法,都是针对文本类的压缩算法,挺有意思,大家有兴趣的可以了解下。

  • 页面链路:渲染(CRP 优化)

浏览器拿到响应体后,就会进入到渲染过程,解析 DOM 树,CSS 树,生成渲染树,计算节点,绘制页面。

这个过程叫做关键渲染路径,对于这类的优化可以统称为 CRP 优化。

CRP(关键渲染路径Critical Rendering Path)是浏览器从收到 HTML、CSS 和 Javascript 字节到对其进行必的处理,从而将它们转化为渲染的像素这一过程。

CRP优化常规步骤:

  1. 关键路径分析和特性描述:关注三种可变因素:资源数、字节数、长度。

  2. 减少资源数。

  3. 缩小字节数。

  4. 缩短路径长度。

为减少资源数,缩小字节数,在工程化体系中,webpack 有很多的 loader 和插件,可以对 CSS,图片,JS 进行压缩和优化。

  • 分析工具:webpack-bundle-analyzer

  • 压缩CSS: css-loader?minimize(cssnano)、PurifyCSSPlugin

  • 压缩图片:image-webpack-loader(imagemin-webpack-plugin)、webpack-spritesmith、url-loader(base64)

  • 压缩JS:UglifyJS插件、ParallelUglifyPlugin

  • 优化JS

    • ‍DllPlugin 提升构建速度

    • splitChunks 拆包

    • 按需加载 import (*)

页面渲染中,尽可能只加载首屏必要的元素可有效减少首屏渲染时间。

在 C 端业务中,图片资源占了页面资源大部分内容,在活动页面中,往往能占到 80% 的资源比例。

针对图片做懒加载,尺寸裁减,webp 等优化,则可以有效地减少加载的资源数,缩小字节数。对于图片懒加载可以同比类推,去实现页面中的模块懒加载,对于非首屏的内容,也没意义在初始渲染的时候进行加载渲染。

首屏渲染中,关注必要的数据请求接口,缩短关键路径长度。

比如页面中初始化的接口,可以采用极简的代码在页面 head 处执行,获取返回数据缓存到内存中,等到业务代码加载执行时可以直接获取缓存数据,理想情况下,就可以节省整个请求的耗时。

这类接口提前对于依赖初始化接口的页面做性能优化非常有效。

4.2.4 成果验收和复盘

实施一系列性能优化策略后,做好最后的成果验收和复盘。

  • 性能优化记录:记录每次策略带来的性能优化,沉淀有效策略

  • 性能周报:同步各业务负责人性能优化数据,以及待提升的页面列表

  • 白皮书:体系化的性能优化流程与策略梳理,团队共享

5. 最佳实践

以上,较完整地介绍了前端性能优化的完整流程和体系。接下来介绍下网易严选业务中一些最佳实践。

5.1 整体架构

网易严选性能优化整体架构如下:

  • 前端性能度量工具:APM 监控平台、性能衡量指标,对应的性能分析工具

  • 前端性能增加基建:C 端页面可以借助端容器做接口预请求和资源预加载

  • 页面接入性能 SDK,上报相关性能数据,针对页面进行性能瓶颈分析,专项优化页面性能和页面品质

5.2 资源预加载 Xcache

缓存是非常有效的一个优化点,但往往是第二次请求才有效,针对第一次请求也想应用到缓存,借助端容器就可以实现。

![Xcache](https://yanxuan.nosdn.127.net/16548311545376231.png?imageView&thumbnail=7 00x0)

资源预加载 Xcache 平台包含以下内容:

  • 管理配置文件的后台。

  • 配置下发服务。

  • 客户端获取配置文件,拉取对应的资源列表,在 webview 发起资源请求时,判断是否命中缓存,命中则直接使用预缓存资源。

  • 对应的行为数据统计。

5.3 静态页面动态化

在接入 Xcache 的过程中,遇到了一个问题。

电商行业有个明显的行业特性,就是页面的秒级切换。严选的营销页面部分是静态页面的,对于一个会场页面投放链接是固定的,比如存在预热期,正式期,返场期,页面内容的切换是通过定时的任务去刷新页面内容,虽然实现了秒级切换,但也意味着页面的 HTML 是不做缓存的,与接入 Xcache 矛盾。

基于现在的页面切换现状,最终采用了静态页面动态化改造的方案。

将一个静态的页面文件内容基于 AST 重新生成 bundlejs,这样对于预热期,正式期,返场期就会拿到三个 page bundlejs,再通过一个动态页面容器,结合条件路由配置信息,判断当前时间,加载不同时段的 page bundlejs,这样就能实现秒级切换,同时也可以将 HTML 和这些 bundlejs 提前缓存到 Xcache 中。

5.4 接口预请求Prefetch

接口预加载,类似于前面提到的接口提前,不同的是,接口预加载是通过容器代为发出,发送的更早,能更好的保证接口提前完成。

5.5 GIF懒加载

 

直接加载 GIF,约 2850.9kb VS 加载 GIF 的第一帧,约 76.9kb

在资源优化过程中,GIF 懒加载有了较好的数据提升,对于 GIF 图,可以只加载 GIF 的第一帧,等首屏渲染完成后,再完整加载 GIF 的资源,约缩小 97% 的首屏图片资源。

5.6 底部导航切换优化

在做了性能优化的基础上,也做了一些体验提升的内容:

 

比如底部导航切换优化,在切换页面时仍能保持底部导航常驻的状态,避免闪动带来的不适感。

5.7 页面过渡效果

主流的 SPA,MPA 框架主要逻辑都集中在 bundlejs 中,在逻辑载入执行之前页面仍然有一段白屏时间值得去优化。

 

可以在页面中插入一段 loading 逻辑,用于添加页面背景色,毛玻璃渐入效果,以及在弱网中的 loading 提示,进一步减少白屏焦虑。

再往前追述,还有 HTML 本身的加载耗时,这一段时间仍然值得去优化,如容器背景色或者 HTML 的缓存。

6. 结语

前面讲了较多的内容,或许你对性能优化流程又有点疑惑了,其实流程很简单,不妨再回顾下整个性能优化的流程。

  1. 我们在有意识的状态下,关注指标和数据,因此要先建设度量体系,其中包含衡量指标和对应的监控平台。

  2. 接入度量体系后,就可以看到当前的业务现状,制定相应的目标

  3. 接下来就是具体的性能优化策略实施

      1. 记住一个关键问题,从输入URL到页面展示经历了什么,抓住对应的关键词:缓存、tcp连接、服务器、响应体、渲染。基于每个关键词去扩展对应的优化手段。

      2. 在渲染中,记住 CRP 关键渲染路径优化 ,核心关注:资源数、字节数、路径长度的优化。

  4. 最后就是成果的验收和复盘

整个文章主要对全流程做了一下介绍,串联了各个优化手段,希望大家后续做一个完整的性能优化时,不再是各个分散的优化点,而是能想起上述的流程图,能完整的串联起各个优化点。


本文由作者授权严选技术团队发布



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存