前端性能优化实战

2023-05-31 0 451

前端性能优化实战
You cant manage what you cant measure. —— Peter Drucker

测度

原文中中提及了 大卫·彼德 的一句话,“两件事假如你难以来衡量它、你就难以管理工作它”,操控性反之亦然这般。假如没两个精确的计划来对操控性展开测度,那强化就难以实现。
所以对他们而言,什么样分项是能用以对网页操控性、使用者新体验展开测度的呢?就要从如下表所示两个视角逐个为他们传授:

Performance API

网页简洁度

FPS

raf(requestAnimationFrame)

首屏操控性

FP、FCP、FMP

CWV(Core Web Vitals)

Performance API

相信后端的同学对 Performance API 应该都不陌生,通常他们将浏览器提供的能展开测算和采集的 API 统称为 Performance API,该类型的对象能通过调用只读属性window.performance来获得。
在日常的工作中,他们为了计算两个任务的耗时,通常会在任务执行前后利用 Date.now() 分别创建两个时间,最后取两者的差值作为任务执行耗时。但是 Date.now() 存在两个问题:

返回的时间戳是从 1970 年 1 月 1 日 00:00:00 UTC 开始经过的毫秒数,依赖于系统时间

精度仅到毫秒(ms)

为了对操控性做精准的计算,他们能选择 Performance API 提供的 performance.now() 来展开高精度计算,其特性为:

时间戳基于网页打开的时间计算

精度精确到微秒(us)

下图能比较直观的看到两者的差异:
前端性能优化实战

网页简洁度

FPS

帧率 FPS(Frames Per Second – 每秒传输帧数),一般对网页而言,最优的帧率在 60 FPS,假如越接近这个值,网页就越简洁,帧率假如远低于这个值,使用者可能会明显感觉到卡顿。

60 FPS 意味着网页每隔 16.5ms(1/60)就需要渲染一次,否则就会出现丢帧的现象,而浏览器中的 JavaScript 执行和网页渲染都是会相互阻塞的,假如在代码中有非常复杂的逻辑占用了大量的执行时长,就会导致网页出现卡顿。

在 Chrome 的 devtools 中他们能执行Cmd+Shift+P 输入 show fps 来快速打开 fps 面板,如下表所示图所示:

前端性能优化实战

通过观察 FPS 面板,他们能很方便的对当前网页的简洁度展开监控

前端性能优化实战

他们在代码中假如想对当前网页的 FPS 帧率展开监控,能参考如下表所示这段示例代码:

var lastTime = performance.now();var frame = 0;varlastFameTime = performance.now();var loop = function(time) { var now = performance.now(); var fs = (now – lastFameTime);lastFameTime = now; var fps = Math.round(1000/fs); frame++; if(now > 1000 + lastTime) { var fps = Math.round((frame * 1000) / (now – lastTime)); frame = 0; lastTime = now; }; window.requestAnimationFrame(loop);}

requestAnimationFrame

window.requestAnimationFrame() 告诉浏览器你希望执行两个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

这里借用 MDN 的描述,顾名思义就是传入两个函数,让浏览器在下一次渲染之前展开调用。所以基于这个特性,结合上面提供的 FPS 计算示例代码,他们能发现,假如他们持续对 requestAnimationFrame 展开调用,所以每次调用的间隔应该在 16.7ms 左右,即满足他们对网页简洁度 60 FPS 的要求,能使用如下表所示代码在控制台执行试试看:

let lastTime = 0;const measure = () => { console.log(`${Date.now() – lastTime}ms`); lastTime = Date.now(); requestAnimationFrame(measure);};measure();

首屏操控性

首屏操控性作为他们最关心的核心分项之一,在操控性强化的场景中占据了相当大的比重,所以对首屏的操控性他们有什么样来衡量分项呢?

针对这个问题,Google 曾经提出过一系列的以使用者新体验为中心的操控性分项。

前端性能优化实战

FP、FCP、FMP

FP(First Paint 译为“首次绘制”)代表浏览器第一次向屏幕传输像素的时间,仅表示当前已经开始绘制了,实际意义比较小。

FCP(First Contentful Paint 译为“首次内容绘制”)代表浏览器第一次向屏幕绘制 “内容”(只有首次绘制文本、图片(包含背景图)、非白色)。

相比之下,FCP 指的是浏览器首次绘制来自 DOM 的内容。例如:文本,图片,SVG,canvas元素等,这个时间点叫 FCP。

FMP(First Meaningful Paint 译为“首次有效绘制”)表示网页中有意义的内容开始出现在屏幕上的时间点。它也是他们来来衡量使用者加载新体验的主要分项。

FMP 本质上是两个主观认知分项,是通过两个算法来猜测某个时间点可能是 FMP,但是计算方式过于复杂而且不精确,后来 Google 也放弃了 FMP 的探测算法,转而采用更加明确的客观分项 – LCP。

CWV(Core Web Vitals)

核心 Web 分项是适用于所有网页的 Web 分项子集,每位网站所有者都应该测量这些分项,并且这些分项还将显示在所有 Google 工具中。每项核心 Web 分项代表使用者新体验的两个不同方面,能够展开实际测量,并且反映出以使用者为中心的关键结果的真实新体验。

目前的 Web 核心分项由三个方面构成 — 网页加载操控性、交互性、视觉稳定性,包含如下表所示三个分项及阈值:

前端性能优化实战

Largest Contentful Paint (LCP):最大内容绘制,测量加载操控性。为了提供良好的使用者新体验,LCP 应在网页首次开始加载后的2.5 秒内发生。

First Input Delay (FID):首次输入延迟,测量交互性。为了提供良好的使用者新体验,网页的 FID 应为100 毫秒或更短。

Cumulative Layout Shift (CLS):累积布局偏移,测量视觉稳定性。为了提供良好的用户新体验,网页的 CLS 应保持在 0.1. 或更少。

1)LCP

面或者骨架屏,并没实际价值,所以 LCP 相较于 FCP 更适合作为首屏分项。

前端性能优化实战

拿 Detail 页举例,在 FCP 时,商品图片并未加载,此时对使用者而言,两个近乎白屏的网页是不具备可交互价值的,在 LCP 时,图片已经完成了加载,首屏主要元素也几乎加载完毕,此时的时间作为首屏时间,才是比较接近使用者体感的。

既然 LCP 是根据网页上占据面积最大的元素渲染时间确定的,所以元素包含什么样呢?

图片

内嵌在 svg 中的 image 元素

视频的封面

通过 url() 加载的 background image

文字

在 webpagetest 上能很直观的看到当前 LCP 元素的详情信息

前端性能优化实战

元素面积的计算规则有如下几点:

在 viewport 内可见元素的大小,假如是超出可视区域或者被裁减、遮挡等,都不算入该元素大小

对图片元素而言,大小是取图片实际大小和原始大小的较小值,即Min(实际大小,原始大小)

对文字元素,只取能够覆盖文字的最小矩形面积

对所有元素,margin、padding、border 等都不算

2)FID

FID 分项是指使用者首次和网站展开交互到浏览器响应该事件的实际延时时间,能想象一下,假如在你点击了两个 button 后,网页没任何变化,2-3s 后才开始响应,可想而知新体验是非常糟糕的。

FID 判定的交互行为有:

点击、触摸、按键等(不包含滚动和缩放)

有事件绑定的行为,比如注册在某个 dom 上的 click 事件

所以为什么会产生交互延迟呢?比如我在 button 上注册了两个 click 事件,例如:

btn.addEventListener(click, () => { // do something})

按照预期,使用者点击按钮的时候,回调函数会被直接触发,但是假如当前主线程被渲染、Long Tasks 占用,这个回调的执行就会被延后,就会导致 FID 时长增加。

但是 FID 作为两个“非客观值”,需要使用者展开交互才能采集到,使用者的交互时机,反之亦然也会对分项的采集、统计造成影响。

3)CLS

CLS 是用以来衡量视觉界面稳定性的两个分项,指的是网页产生的连续累计布局偏移分数。他们在日常业务中经常会用到懒加载、骨架屏等方式,用较低的成本先展示网页框架,再用动态渲染的方式,来对网页内容展开填充,假这般时布局发生变化,比如动态加载的元素和原本占位的元素大小不一致,可能就会导致使用者误操作,影响使用者新体验,CLS 就是为了测度这类问题而存在。

当他们在说布局偏移的时候,指的是:网页中两个可见元素的起始位置发生改变,而元素的增删则并不会触发布局偏移。

所以如何定义偏移的连续累计呢?有如下表所示两个要素:

CLS 计算的并非网页整个周期的偏移分数之和,而是累计值最高的连续布局偏移

偏移相隔的时间少于 1s,且整个窗口的最大持续时间为 5s,则被计为连续偏移

分析工具

DevTools

DevTools 算是和前端同学打交道最多的工具之一了,主要用以查看日志、查看网络请求、debug 网页等等,他们同时还能利用它对网页操控性展开分析。

Network

前端性能优化实战

如上图所示,这是他们很熟悉的 Network 界面,功能上我用红框大概做了一下划分:

选项区:Preverse Log 能在面板中保留网络请求,在网页重定向、当页跳转时能保留之前网页的日志;Disable Cache能屏蔽浏览器的 http 缓存机制;右侧的 No throtting 选择器能对当前网络状态展开模拟(Fast 3G、Slow 3G 等等)

请求列表、请求状态

请求传输体积:默认展示 gzip/br 压缩后的大小

Waterfall:资源加载的时序和每一步的耗时

Performance

Performance 面板能提供更加专业的操控性信息

前端性能优化实战

WebPageTest

WebPageTest是两个线上操控性分析平台,除了常用的 cwv 操控性数据外,还有 performance、lighthouse 报告、网页对比等功能。

输入 URL 后他们能简单的选择两个 simple configuration 展开测试,默认会执行 3 次测试。这里他们能看到网页的一些核心分项,能点开对应的分项项展开更详细的分析,在 Waterfall 网页他们也能很直观的看到当前网页的请求顺序、请求耗时、关键节点(FCP、LCP等等)

前端性能优化实战

强化手段

网络传输强化

前端性能优化实战

这里他们着重看三个时间分项:

Total Connection Time:整体的连接耗时

TTFB(Time to First Byte):首字节传输耗时

Content Download:内容传输耗时

Total Connection Time

导致连接耗时长的因素可能会有很多种:

机器距离使用者端的物理距离过长(美国 – 中国)

重复建联,在网页中使用了多个不同域名,每次都需要重新建立连接

使用者端网络环境问题

所以为了解决这些问题他们能采取什么样手段呢:

利用 CDN 对主域名展开动态加速,对资源域名展开缓存,利用边缘节点的特性缩短使用者请求距离

利用 pre-connect 对域名展开预建联,同时对域名展开收拢,这样在 http2 的情况下能减少建联耗时

充分利用 http 缓存和 servicesworker 请求拦截的特性,对可缓存的资源展开本地缓存,减少发起网络请求次数

TTFB + Content Download

TTFB 是从发起请求到收到服务器请求第两个字节的时间,一般而言,假如首屏 html 请求的 TTFB 能达到 100ms 以内,就已经具备不错的新体验了,假如超过了 500ms,所以使用者就能明显的感受到白屏,精准的而言,TTFB 是在完成 DNS 查询、TCP 握手、SSL 握手后发起 HTTP 请求报文到接收到服务端第两个响应报文的时间差,大约等于 两个RTT(Round-Trip Time 即往返时延)+ ServerRT。

所以当 TTFB 耗时很长时,如何展开强化呢?能参考如下表所示几种方式:

减少请求传输量,避免无用信息

减少服务端处理时间(增加缓存、慢 SQL 治理等等)

对首屏 HTML 内容做流式渲染,由于浏览器对 HTML 的解析并不依赖与下载完整的 HTML,而是解析一部分渲染一部分,所以服务端能先将部分准备好的内容通过流式渲染的方式返回,而不是等全部内容就绪后再返回

懒加载:优先返回必要内容,例如超长网页,能先返回首屏看到的内容,剩下的通过异步加载的方式展开渲染,分多个接口展开请求

所以,是 TTFB 越短越好吗?

其实也不尽然,他们需要做好 TTFB 和 Content Dow使用者真实的新体验,而不是一味地盯着时间展开强化。

preload

preload 也就是预加载,关于预加载的方式有很多种,端内和端外也各自有不同的计划,比较常见的有:

preload 标签:<link rel=”preload” as=”image” href=”xxx” />

serviceworker 预加载:flasher、workbox-preload 等

zcache:在客户端端内通过资源离线包的方式展开预加载

相关链接

Lighthouse Scoring Calculator

https://googlechrome.github.io/lighthouse/scorecalc/

WebPageTest

https://www.webpagetest.org/

Web Vitals

https://web.dev/vitals/

web-vitals – Github

https://github.com/GoogleChrome/web-vitals

举报/反馈

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务