Lighthouse Web性能分析和优化实践

Web 性能包含了服务器请求和响应、加载、执行脚本、渲染、布局和绘制每个像素到屏幕上。

本文以 Lighthouse Report 来深入学习 web性能指标及性能优化点

1. 为什么要关注Web性能

Web 性能直接影响网站业务指标,例如转换率和用户满意度

2. Lighthouse

  • lighthouse是一个开源的自动化工具,用于改进网络应用的质量

  • Lighthouse报告分析了加载页面生命周期中的各种性能指标

// 安装lighthouse:
npm install -g lighthouse
// 2. 运行使用
lighthouse https://m.jd.com --locale zh --quiet --chrome-flags="--headless" --only-categories=performance

还有一些Web网站基于lighthouse 提供服务,你可以登录这些网站输入URL检测网络性能。

webpagetest是一个免费的网站性能测试工具

  • Calibre

https://calibreapp.com/

  • Debug bear

https://www.debugbear.com/

3. Lighthouse 性能指标

####

##### 3.1.1 记录FP和FCP

* First_paint

3.1.1.1 安装依赖本地分析网页性能指标
### 1. 依赖 node 环境

```
npm install express morgan compression --save
```

#### 2. 编写配置文件 perf.js

#### 3. 启动方式

```
    进入site目录
    执行 : nodemon index.js
```
3.1.1.2 site\index.js

site\index.js

const express = require('express')
const logger = require('morgan')
const app = express()
app.use(logger('div'))
app.use((req, res, next) => {
	next()
})
app.use(express.static('public'))
app.listen(80, () => console.log('服务器已经在80端口启动了……'))
3.1.1.3 delayConfig.js
const delayConfig = {
	'/index.html': 1000,
	'/1.jpg': 1000,
}
module.exports = delayConfig
3.1.1.4 index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lighthouse</title>
    <link rel="ens-prefetch" href="//static.360buyimg.com">
</head>

<body>
    <canvas></canvas>
    <div>hello</div>

    <script src="/perf.js"></script>
</body>

</html>
3.1.1.5 perf.js
;(function (ready) {
	if (
		document.readyState === 'complete' ||
		document.readyState === 'interactive'
	) {
		ready()
	} else {
		document.addEventListener('readystatechange', () => {
			if (document.readyState === 'complete') {
				ready()
			}
		})
	}
})(function perf() {
	const data = {
		FP: 0, // 首次绘制
		FCP: 0, // 首次内容绘制
		LCP: 0, // 最大内容绘制
		FID: 0, // 首次交互延迟
		CLS: 0, //
	}
	// 如果观察者观察到了指定类型的性能条目,就执行回调
	new PerformanceObserver(function (entryList) {
		let entries = entryList.getEntries()
		entries.forEach((entry) => {
			if (entry.name === 'first-paint') {
				//首次绘制的开始时间
				data.FP = entry.startTime
				console.log('记录FP', data.FP)
			} else if (entry.name === 'first-contentful-paint') {
				data.FCP = entry.startTime
				console.log('记录FCP', data.FCP)
			}
		})
	}).observe({
		type: 'paint',
		buffered: true,
	})

	new PerformanceObserver(function (entryList) {
		let entries = entryList.getEntries()
		entries.forEach((entry) => {
			if (entry.startTime > data.LCP) {
				console.log('记录LCP', (data.LCP = entry.startTime))
			}
		})
	}).observe({
		type: 'largest-contentful-paint',
		buffered: true,
	})

	new PerformanceObserver(function (entryList) {
		let entries = entryList.getEntries()
		entries.forEach((entry) => {
			// 首次用户交互开始处理的时间减去 开始交互的时间 就是首次交互延迟
			const FID = entry.processingStart - entry.startTime
			console.log('FID', FID, entry)
		})
	}).observe({
		type: 'first-input',
		buffered: true,
	})

	new PerformanceObserver(function (entryList) {
		let entries = entryList.getEntries()
		entries.forEach((entry) => {
			data.CLS += entry.value
			console.log('CLS', data.CLS)
		})
	}).observe({
		type: 'layout-shift',
		buffered: true,
	})
})
3.1.2 改进FP和FCP
  • 加快服务器响应速度

升级服务器的配置
合理设置缓存
优化数据库索引
  • 加大服务器带宽

  • 服务器开启gzip压缩

  • 开启服务器缓存(redis)

  • 避免重定向操作

  • 使用 dns-prefetch 进行DNS进行预解析

  • 采用域名分片技术突破同域6个TCP链接限制或采用HTTP2

  • 使用CDN减少网络跳转

  • 压缩JS和CSS 和图片等资源

TerserWebpackPlugin
purgecss-webpack-plugin
  • 减少HTTP请求,合并JS和CSS,合理内嵌JS和CSS

3.1.2.1 site\index.js
3.1.2.2 index.html
3.2 SI

Speed Index(速度指标) 表明网页内容的课件填充速度

速度指数衡量页面加载期间内容的视觉显示速度

##### 3.2.1 如何改进 SI

3.2.1.1 最小化主线程工作
  • 最小化主线程工作

  • 脚本

优化第三方的JS脚本
对输入进行防抖处理
使用 web workers
  • 样式和布局

缩小样式计算的范围并降低其复杂性
避免复杂的布局和 布局抖动
  • 渲染

坚持仅合成器的属性和管理层计数
简化绘制的复杂度、减小绘制区域
  • 解析HTML和CSS

提取关键CSS
压缩CSSS
延迟加载非关键CSS
  • 脚本解析和编译

通过代码拆分减少JS的负载
删除未使用的JS
  • 垃圾收集

监控网页的总内存使用情况
3.2.1.2 减少Javascript执行时间

* 减少Javascript 执行时间

* 通过代码分割仅发送用户需要的代码

* 压缩代码

* 删除未使用的代码

* 使用PRPL模式缓存你的代码减少网络开销

3.2.1.3 确保文本在webfont加载期间保持可见
  • 确保文本在 webfont 加载期间保持可见

  • 字体通常是需要一段时间才能加载的大文件,一些浏览器在字体加载之前隐藏文本,导致不可见文本(FOIT)闪烁

  • 通过包含font-display: swap在 您的@font-face分格中,您可以在大多数现代浏览器避免FOIT

@font-face {
  font-family: 'Pacifico';
  font-style: normal;
  font-weight: 400;
  src:local('Pacifico Regular'), local('Pacifico-Regular'),url(https://fonts.gstatic.com/s/pacifico/v12/FwZY7-Qmy14u9lezJ-6H6MmBp0u-.woof2) format('woff2');
  font-display: swap;
}
3.2.1.4 web workers
3.2.1.5 避免强制同步布局和布局抖动
3.3 LCP
  • Largest Contentful Paint(最大内容绘制)标记了渲染出最大文本或图片的时间

  • 最大内容绘制(LCP)是测量感知加载速度的一个以用户为中心的指标

3.2.2 改进LCP
  • 改进LCP

  • 使用PRPL模式做到及时加载

推送(或预加载)最重要的资源Preload是一个声明的获取请求,它告诉浏览器尽快请求资源
尽快渲染初始路线 内联首屏JS和CSS其余部分
预渲染存剩余资源 Service Worker
延迟加载其他路由和非关键资源
  • 优化关键渲染路径

  • 优化您的图像

  • 优化网页字体

  • 优化您的JavaScript

<link rel="preload" as="style" href="css/style.css">
3.4 TTI
  • Time to Interactive(可交互时间)指标测量页面从开始加载到主要资源完成渲染,并能够快速、可靠地响应用户输入所需的时间

  • webpagetest

  • 虽然TTI 可以在实际情况下进行测量,但我们不建议这样做,因为用户交互会影响您的网页的TTI,从而导致您的报告中出现大量差异。如需了解页面在实际情况中的交互性,您应该测量First Input Delay 首次输入延迟(FID)

3.4.1 改进TTI
  • 缩小Javascript

  • 预连接到所需的来源

  • 预加载关键请求

  • 减少第三方代码的速度

  • 最小化关键请求深度

  • 减少Javascript执行时间

  • 最小化主线程工作

  • 保持较低的请求数和较小的传输大小

3.5 TBT
  • total Blocking Time(总阻塞时间)指标测量First Contentful Paint 首次内容绘制(FCP)与 TIme to Interactive可交互时间(TTI)之间的总时间,这期间,主进程被阻塞时间过长,无法作出输入响应

  • 虽然TBT可以在实际情况下进行测量,但我们不建议这样做,因为用户交互会影响您网页的TBT,从而导致您的报告中出现大量差异。如需了解页面在实际情况中的交互性,您应该测量First input Delay 首次输入延迟(FID)

3.5.1 如何改进 TBT

* 减少第三方代码的影响

* 减少Javascript执行时间

* 最小化主线程工作

* 保持较低的请求数和较小的传输大小

3.6 FID
  • 首次输入延迟(FID)是测量加载响应度的一个以用户为中心的重要指标

  • 因为该项指标用户尝试与无响应页面进行交互时的体验进行了量化,低FID有助于让用户确信页面是有效的

  • 首次输入延迟(FID)指标有助于衡量您的用户对网站交互性和响应度的第一印象

  • FID 测量从用户第一次与页面交互(例如他们单击链接、点按钮或适应由Javascript驱动自定义控件)直到浏览器对交互作出响应,并实际能够开始处理事件处理程序所经过的时间

3.6.1 测试FID
3.6.1.1 PERF.JS

site\public\perf.js

;(function (ready) {
    if (
        document.readyState === 'complete' ||
        document.readyState === 'interactive'
    ) {
        ready()
    } else {
        document.addEventListener('readystatechange', () => {
            if (document.readyState === 'complete') {
                ready()
            }
        })
    }
})(function perf() {
    const data = {
        FP: 0, // 首次绘制
        FCP: 0, // 首次内容绘制
        LCP: 0, // 最大内容绘制
        FID: 0, // 首次交互延迟
        CLS: 0, //
    }
    // 如果观察者观察到了指定类型的性能条目,就执行回调
    new PerformanceObserver(function (entryList) {
        let entries = entryList.getEntries()
        entries.forEach((entry) => {
            if (entry.name === 'first-paint') {
                //首次绘制的开始时间
                data.FP = entry.startTime
                console.log('记录FP', data.FP)
            } else if (entry.name === 'first-contentful-paint') {
                data.FCP = entry.startTime
                console.log('记录FCP', data.FCP)
            }
        })
    }).observe({
        type: 'paint',
        buffered: true,
    })

    new PerformanceObserver(function (entryList) {
        let entries = entryList.getEntries()
        entries.forEach((entry) => {
            if (entry.startTime > data.LCP) {
                console.log('记录LCP', (data.LCP = entry.startTime))
            }
        })
    }).observe({
        type: 'largest-contentful-paint',
        buffered: true,
    })

    new PerformanceObserver(function (entryList) {
        let entries = entryList.getEntries()
        entries.forEach((entry) => {
            // 首次用户交互开始处理的时间减去 开始交互的时间 就是首次交互延迟
            const FID = entry.processingStart - entry.startTime
            console.log('FID', FID, entry)
        })
    }).observe({
        type: 'first-input',
        buffered: true,
    })

    new PerformanceObserver(function (entryList) {
        let entries = entryList.getEntries()
        entries.forEach((entry) => {
            data.CLS += entry.value
            console.log('CLS', data.CLS)
        })
    }).observe({
        type: 'layout-shift',
        buffered: true,
    })
})
3.6.2 改进FID
  • 减少第三方代码的影响

  • 减少Javascript执行时间

  • 最小化主线程工作

  • 保持较低的请求数和较小的传输大小

3.7 CLS
  • CLS 测量整个页面生命周期内所发生的所有意外布局偏移中最大一连串的布局偏移分数

3.7.1 如何计算CLS
3.7.1.1 perf.js

site\public\perf.js

(function (ready){
	if(document.readyState === "complete" || document.readyState = "interactive"){
		ready();
	}else{
		document.addEventListener("readystatechange", function(){
			if(document.readyState === "complete"){
				ready();
			}
		})
	}
 })(function perf(){
 	var data = {
		url: window.location.href,
		FP: 0,
		FCP:0,
		LCP:0,
		CLS: 0,
	}
 })
3.7.2 如何改进CLS
  • 始终在您的图像和视频元素上包含尺寸属性

  • 首选转换动画,而不是触发布局偏移的属性动画

  • 除非是对用户交互做出响应,否则切勿在现有内容上方插入内容

4. performance面板

Lighthouse优化

性能指标

优化建议 & 详细(看Lighthouse 报告)

诊断结果 & 建议(看Lighthouse 报告)

TP90

科普一下TP90概念,其中TP = Top Percentile,Top 百分位数,也有叫90 percent;

假设你统计了一段时间内访问系统的100次请求数据,他们的响应耗时分别是:1ms、2ms、3ms...100ms。基于本次统计结果,你系统的 TP90,请求耗时从小到大排列,为90ms(代表 90% 请求响应不超过90ms),这个响应时间更接近用户的体验(90%的用户体验都是小于90ms的);

如果要求再高点,可以取TP99,这里就是99ms(99%的用户体验都是小于99ms的);

为什么不取平均响应时间?

这里平均响应时间大约是50ms,如果你说你的响应时间是50ms,但是实际上,有一半的用户体验是大于50ms的,这就不太好了。

浏览器兼容

### Lighthouse 网页性能分析以京东官网测试为例

##  准备node.js 环境
1.新建项目 npm init -y 初始化工程
2. 安装好lighthouse 
npm install -g lighthouse
3. 执行以下命令
lighthouse https://m.jd.com --locale-zh --quiet --chrome-flags="--headless" --only-categories=performance

本文学习参考来源:“腾讯课堂---珠峰网络公开课”

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值