如何着手网页性能优化
1. 简单了解
优化性能我们首先需要了解用户访问页面时发生了什么,这样方便我们定位当前页面的瓶颈在哪,更好的解决问题。
1.1 浏览器展现顺序

a.首次绘制(First Paint,FP)
FP是所有指标中发生的第一个,这个指标表示页面首次绘制的时间点,换句话说它表示当用户第一次看到白屏的时间点,但是他在图层进行绘制的时候触发,而不是文本、图片或 Canvas 出现的时候,所以它通常没有多少意义。标准定义
b.首次内容绘制(First Contentful Paint,FCP)
这是当用户看见一些“内容”元素被绘制在页面上的时间点。和白屏是不一样的,它可以是文本的首次出现,或者 SVG 的首次出现,或者 Canvas 的首次出现等等。如果FCP时间慢,通常有以下两个原因:
- 首次下载的资源过于大
- 用户网络状况差
c.首次有意义绘制(First Meaningful Paint,FMP)
指页面主要内容出现在屏幕上的时间点,他的计算通常是chromium通过收集所有布局变化,然后计算变化最大的一次所记录下来的时间,这个时间就是FMP如果FMP时间慢,通常有以下两个原因:
- 图片、样式、字体、js的资源具有较高的优先级,阻塞了FMP
- js的执行时间过长,导致页面关键元素的渲染被推后
d. 首次交互(Time to First Interactive, TTI)
指页面已经准备好并可以使用,chrome的计算通常是需要满足以下条件:
- FMP
- DOMContentLoaded触发 (domready)
- 页面85%以上已经被渲染
1.2 页面生命周期


在浏览器加载的顺序以及页面生命周期中都有可能发现性能问题:如在网络资源加载部分,优先级通常如下:高:CSS、font、同步请求中:JS、Ajax低:image、推迟加载的资源
最终我们在各个阶段中,可以考虑的方案大纲:

2. 优化的指标
每次的优化都需要有指标去量化衡量。优化的目标通常是为了加快对用户的 视觉反馈 & 操作反馈
2.1 视觉反馈
- 白屏时间
- 首屏(需要人为定义: 关键图片/文字加载出来的时间)
2.2 操作反馈
- TTI
- 资源load完毕
2.3 采集的指标 采集的数据均可从performance Timing API上获取
- DNS: domainLookupEnd - domainLookupStart
- TCP :connectEnd - connectStart
- request:requestEnd - requestStart
- response:responseEnd - responseStart
- resource:performance.getEntriesByType('resource')
- first paint(白屏):
- performance.getEntriesByType('paint')[0].startTime
- load.firstPaintTime - load.startLoadTime (chrome中)
- TTI:domInteractive - navigationStart
- domReady: domContentLoadedEventEnd - navigationStart
- onload:loadEventEnd - navigationStart
3. 定位分析
3.1 数据分析
性能方案的制定通常需要与页面的数据分析相结合,所以在每个阶段的优化功能上线,都需要得出优化是正向还是负向,以及优化的预期,可视化监控平台,如:grafana

3.1.1 可视化平台 grafana


分位数: 亦称分位点,是指将一个随机变量的概率分布范围分为几个等份的数值点 (百分比的人都在该数据以下)
通过上面两个平台可以看到按照分位数的看大盘的平均情况,但是对于需要得出各时段的分布区间或想查看不同类型下的表现,则需要跑hive数据得出:
3.1.2 数据分析平台
jupyterhub(支持python3在线分析数据)
引入 Pandas库 进行区间的分析(Pandas是Python第三方库,提供高性能易用数据类型和分析工具. )
3.2 性能分析
可以使用一些工具来帮助我们对单个页面进行分析:
3.2.1 Chrome performance
Performance通常可以定位以下问题:
- 资源加载顺序
- 执行时间
- cpu是否占用过高


3.2.2 Lighthouse & Chrome Audits & PageTest
这三类工具是集成性能分析工具,会对页面整体的性能进行分析,同时给出整体优化建议


3.2.3 webpack-bundle-analyzer
在具体项目构建中,可以使用插件对源码使用中的库及第三方插件大小进行分析:优化前:

优化后:

3.2.4 webspeedtest图片分析网站
webspeedtest会根据目前网站使用的图给出可能的优化点
优化前:

优化后:

4.优化方式
在根据对页面的分析以及结合落地页特性,我们给出了以下阶段的方案:


4.1 体积减小
体积减小通常包含三个方面:
- 代码体积
- 组件/库的按需加载(动态import,requre.ensure)
- split chunk 对js代码进行拆包
- tree shaking 移除 JavaScript 上下文中的未引用代码(dead-code)
- lazyload 对于不重要的资源惰性加载
- 利用peerdependencies / webpack externals排除多个包的共用代码
2. 图片体积
- 压缩/替换格式 在支持webp格式的手机上使用webp图片
- 响应式图片 不同设备加载不同宽高的图片,有利于减小体积
- lazyload 首屏以外的图片懒加载
- jqeg 渐进式图片 模糊轮廓,渐进清晰
3. 字体体积
- 预加载
- 避免艺术字体包
4.2 图片lazyloadlazyload通常有两种方案:
- 监听scroll事件,真实地址放在data-src,通过getClientRect实时计算每个dom是否进入视窗,然后替换


IntersectionObserver需要接收三个参数,root:视窗节点(蓝色部分) rootMargin:距离视窗的多少距离(虚线部分,相当于对视窗的扩充) threshold:交叉比例达到多少时触发回调

4.3 其他手段
- 延迟 / async 非重要的js执行
- 利用dns prefetch 并适当增加域名散列
- http 2 多路复用
- webworker 独立js线程计算,避免UI阻塞
- serviceworker离线缓存资源
5. 最后
- 所有的优化方向只是根据数据分析出来针对现阶段的优化手段
- 分析页面的特性,页面形式是否一致, 如广告页场景,每个页面都没有共性,加大首屏优化难度
- 持续对数据的分析,数据时长监控
- 按资源类型 js, css ,image
- 按请求类型 http 1.1 http2.0 DNS TTFB
- 按页面的类型 文字占多数页 / 图片占多数页 / 其他