性能文章>【全网首发】网易莫朽老师:如何从零开始做前端性能优化>

【全网首发】网易莫朽老师:如何从零开始做前端性能优化原创

2年前
5736312

性能优化作为一个老生常谈的项目,能在网上看到各种优化点,但对于一个新手来说,要着手一个完整的性能优化项目,却不知从何下手。

这篇文章将介绍下如何从零开始做性能优化,介绍如何将性能优化项目落地、推进、实施,对业务赋能等。

一、先来一个面试

首先,先来一个面试题:请你介绍下前端性能优化?

(不妨在浏览下方内容前,先自我回答下这个问题。)

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

二、文档目录

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

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

  1. 1. 为什么要做?(为什么需要对项目做性能优化,前端性能优化的价值在哪里?)
  2. 2. 如何做?(如何做一个完整的性能优化,如何下手?)
  3. 3. 最佳实践(网易严选业务中比较有效且特殊的策略分享)
  4. 4. 结语(整个内容的回顾)

1. 为什么要做?

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

用户体验金字塔

体验金字塔
体验金字塔

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

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

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

性能优化业务价值

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

性能优化业务价值
性能优化业务价值

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

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

2. 如何做?

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

意识阶段

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

意识状态
意识状态

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

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

性能体验提升流程

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

  • • 1) 建设度量体系(确定性能衡量指标,建设性能监控平台)
  • • 2) 制定目标(度量体系接入&现状数据分析)
  • • 3) 性能优化实施(团队组织和项目推进,产出优化策略)
  • • 4) 成果验收和复盘

1)建设度量体系

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

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

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

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

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

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

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

第二阶段:W3C标准时期

W3C标准时期
W3C标准时期

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

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

感官性能优化指标
感官性能优化指标

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

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

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

捕获FMP原理

成为FMP元素的条件

成为FMP元素的条件
成为FMP元素的条件

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

FMP算法设计

算法设计
算法设计

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

  1. 1. 通过监听元素加载
  2. 2. 根据可视区域面积,元素权重等关系,计算元素的得分
  3. 3. 把子元素的得分之和父元素得分做比对,取较大值,得到可视区域内得分最高的元素集合。
  4. 4. 过滤分数超过平均分的元素,拿到更小范围的元素集合。
  5. 5. 再对这些元素取最大的加载时间,这个时间则可以用来作为 FMP 的时间。

建设性能监控平台

性能监控平台
性能监控平台

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

  • • 数据可视化:可以直观的看到各业务的实时数据大盘
  • • 慢加载追踪:提供慢页面列表和多维度数据
  • • 性能瓶颈定位:可以针对性的查看某个用户访问路径,查看用户各节点的性能瓶颈
  • • 性能报警:性能报告和线上报警

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

2)制定目标

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

现状数据分析
现状数据分析

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

3)性能优化实施

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

团队组织和整体思路

整体思路
整体思路

先理一下思路

  1. 1. 我们可以基于衡量指标制作一个性能分析工具,专项的分析页面性能瓶颈
  2. 2. 使用常规的性能优化策略,结合严选业务的优化策略
  3. 3. 记录每次性能优化的数据变化
  4. 4. 沉淀有效策略
  5. 5. 在团队各业务中快速落地

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

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

分析

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

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

页面链路
页面链路

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

  1. 1. 输入 URL 地址
  2. 2. 缓存解析
  3. 3. 域名分析
  4. 4. TCP 连接
  5. 5. 服务器响应
  6. 6. 浏览器渲染

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

页面链路:缓存

缓存
缓存

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

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

TCP连接
TCP连接

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

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

cdn服务器
cdn服务器

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

页面链路:响应体(GZIP)

GZIP
GZIP

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

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

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

渲染过程
渲染过程

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

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

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

CRP优化常规步骤:

  1. 1. 关键路径分析和特性描述:关注三种可变因素:资源数、字节数、长度。
  2. 2. 减少资源数
  3. 3. 缩小字节数
  4. 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)成果验收和复盘

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

  • • 性能优化记录:记录每次策略带来的性能优化,沉淀有效策略
  • • 性能周报:同步各业务负责人性能优化数据,以及待提升的页面列表
  • • 白皮书:体系化的性能优化流程与策略梳理,团队共享

3. 最佳实践

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

整体架构

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

整体架构
整体架构
  • • 前端性能度量工具:APM 监控平台、性能衡量指标,对应的性能分析工具
  • • 前端性能增加基建:C 端页面可以借助端容器做接口预请求和资源预加载
  • • 页面接入性能 SDK,上报相关性能数据,针对页面进行性能瓶颈分析,专项优化页面性能和页面品质

资源预加载 Xcache

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

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

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

  • • 管理配置文件的后台
  • • 配置下发服务
  • • 客户端获取配置文件,拉取对应的资源列表,在 webview 发起资源请求时,判断是否命中缓存,命中则直接使用预缓存资源。
  • • 对应的行为数据统计

静态页面动态化

页面切换
页面切换

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

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

静态页面动态化
静态页面动态化

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

接口预请求Prefetch

prefetch
prefetch

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

GIF懒加载

Gif
Gif
Gif第一帧
Gif第一帧

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

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

底部导航切换优化

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

某会场
某会场
某栏目
某栏目

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

底部导航优化
底部导航优化

页面过渡效果

bundlejs
bundlejs

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

慢网效果
慢网效果
快网效果
快网效果

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

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

4. 结语

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

流程图
流程图
  1. 1. 我们在有意识的状态下,关注指标和数据,因此要先建设度量体系,其中包含衡量指标和对应的监控平台。
  2. 2. 接入度量体系后,就可以看到当前的业务现状,制定相应的目标
  3. 3. 接下来就是具体的性能优化策略实施
    1. 1. 记住一个关键问题,从输入URL到页面展示经历了什么,抓住对应的关键词:缓存、tcp连接、服务器、响应体、渲染。基于每个关键词去扩展对应的优化手段。
    2. 2. 在渲染中,记住 CRP 关键渲染路径优化 ,核心关注:资源数、字节数、路径长度的优化。
  4. 4. 最后就是成果的验收和复盘

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

 

💥看到这里的你,如果对于我写的内容很感兴趣,有任何疑问,欢迎在下面留言📥,会第一次时间给大家解答,谢谢!

点赞收藏
莫朽
请先登录,查看3条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步
12
3