一些评估和优化网页性能的指标

111 阅读4分钟

Core Web Vitals - 网页核心性能指标

Google 提出 => 可衡量的、能够真实反应用户体验的: 加载、交互、视觉稳定性

LCP - 最大内容渲染 衡量装载性能

前2.5s内进行最大内容的渲染 a. 最大内容包含了哪些? <img> 元素 <svg> 元素 <video> 元素 通过url()去加载的背景元素 包含文本整体节点的块级元素

b. LCP值低下的原因 服务加载慢 阻断渲染的JS 资源加载 客户端渲染机器性能的影响

c. 针对性改造

服务优化 缓存: HTML离线页面、缓存页面资源、缓存请求 => 缓存机制 资源 尽量减少资源加载渲染:CSS和JS做模块集联拆分、内联 & 合并 => 浏览器原理

图片、文件格式优化 WEBP => 降低资源大小 => 加快加载的速度

请求加速 CDN 云服务 => 工程化压缩、优化

FID - 首次输入时延

衡量页面交互性

页面首次输入的延迟应当小于100ms a. JS的执行时间过长 缩小并减少JS的体量 延迟后置不必要的JS操作 尽量减少不必要的polyfill

b. 分解耗时的任务 长任务 - 任何阻塞主线程超过50ms的 长任务拆解成较小的异步任务

c. worker

 navigator.serviceWorker.register('./service-worker.js')

 // service-worker.js
 self.addEventListener('install', () => {
     // worker初始化
 })
 self.addEventListener('run', () => {
     // worker执行run命令
 })
 self.addEventListener('push', () => {
     // worker初始化
 })
 self.onmessage = e => {
     // 工作
     self.postMessage(workResult)
 }

CLS - 布局偏移(衡量视觉稳定性)

累积布局偏移。它衡量的是页面在加载期间发生意外布局偏移的频率和幅度。CLS 得分应小于 0.1。

假设一个页面在加载过程中,元素的突然移动导致布局变化较大,就会对 CLS 产生负面影响。

布局的移动在可能发生在可见元素的相邻两帧间的位置 a. 不使用无尺寸元素 => srcset sizes b. 减少内容的插入 => 影响整体布局 c. 动态字体的控制

说人话就是,不能因为数据加载,导致布局变来变去的,比如内容还没加载出来,盒子高度为2px,加载出来后变成了20px之类的,推荐最开始就把盒子高度设置为20px

其他页面性能指标

FP:首次绘制

First Paint:标记浏览器渲染任何在视觉上不同于导航前屏幕内容之内容的时间点

FCP:首次内容绘制

First Contentful Paint:标记的是浏览器渲染来自 DOM 第一位内容的时间点,该内容可能是文本、图像、SVG等

FMP:首次有效绘制

First Meaningful Paint:首次有效绘制,标记主角元素渲染完成的时间点,主角元素可以是视频网站的视频控件,内容网站的页面框架也可以是资源网站的头图等

TTI:页面可交互时间

Time to Interactive:页面可交互时间,即从页面开始加载,一直到用户可以自由输入或操作页面的时间

静态资源(js,css,img)加载时间

动态资源加载时间

数据上报方式

测量好时间后,就需要将数据发送给服务端。页面性能统计数据对丢失率要求比较低,且性能统计应该在尽量不影响主流程的逻辑和页面性能的前提下进行。

使用的img标签get请求

  • 不存在AJAX跨域问题,可做跨源的请求
  • 很古老的标签,没有浏览器兼容性问题
var i = new Image();
i.onload = i.onerror = i.onabort = function () {
  i = i.onload = i.onerror = i.onabort = null;
}
i.src = url;

navigator.sendBeacon

大部分现代浏览器都支持 navigator.sendBeacon方法。这个方法可以用来发送一些统计和诊断的小量数据,特别适合上报统计的场景。

  • 数据可靠,浏览器关闭请求也照样能发
  • 异步执行,不会影响下一页面的加载
  • API使用简单
    • 使用express的node服务端需要在接口使用express.text()中间件,才能解析到body
window.addEventListener('unload', logData, false);

function logData() {
    navigator.sendBeacon("/log", analyticsData);
}
const express = require('express');
const app = express();
app.use(express.text());
app.post('/api/someEndpoint', function (req, res) {
    console.log(req.body); // 可以获取到navigator.sendBeacon发送的文本内容
    res.send('Data received');
});
app.listen(3000, function () {
    console.log('Server running on port 3000');
});

最终方案

当浏览器支持sendBeacon方法,优先使用该方法,使用img方式降级上报。