一、使用方式:
- Chrome 开发者工具(DevTools)
- Chrome 扩展
- Node CLI
- Node Modul
二、测试大致流程
Lighthouse 与浏览器建立连接。
测试的初始化配置与加载待测试页面。
在页面加载过程中,运行一系列的采集器(gatherers),每个采集器都会收集自己的目标信息,并生成中间产物(artifacts)。
运行一系列的审计项(audits),每个审计项都会从中间产物(artifacts)中获取所需的数据,计算出各自的评分。
基于审计项的评分计算出大类的评分,汇总生成报告,报告可以以html和json的格式保存。
三、内部原理
https://github.com/GoogleChrome/lighthouse/blob/master/docs/architecture.md
官方给出的模块图:
可以看出有四个重要模块:
Driver、Gatherers、Audits、Categoties
Driver
作用:对chrome进行操控和消息接收、模拟器的设置、记录事件日志
原理:puppeteer + webSockect + devtools(Chrome DevTools Protocol)协议
driver模版的connection实例初始化时,通过 --remote-debugging-port 来设置chrome的远程调试端口为8041,并通过该端口来控制chrome打开一个新的Tab,并返回该Tab的一些信息
拿到上一步中的Tab信息后,通过使用webSocketDebuggerUrl来与浏览器建立Websockeckt连接,之后就可以进行双向通信
建立连接之后,通过Chrome DevTools Protocol协议(文档)来进行通信,调用指令或定义事件,并接收浏览器的相关推送。
driver模块中的emulation(仿真器)可模拟测试设备,如移动端 / PC 端、屏幕的尺寸,模拟设备的 UserAgent、Cookie、网络限速等。
Gatherers
作用:控制页面如何加载,决定页面在加载的过程中采集哪些信息,并生成中间产物 artifacts
原理:gatherer会在页面加载的不同阶段介入,通过driver模块的方法调用定义好的函数来收集目标数据,并将数据存入artifacts,当 pass 中定义的所有 gatherer 运行完后,就会生成一个完整的中间产物 artifacts
1、用户可以通过定义passes字段来定义getherers的行为:
{
passes: [{ // 数组中每增加一项,都会使页面重新加载一次
passName: 'defaultPass',
recordTrace: true, // 是否记录Trace信息
useThrottling: true, // 是否使用限速
gatherers: [ // gatherers列表
'css-usage',
'viewport-dimensions',
'runtime-exceptions',
'console-messages',
'anchor-elements',
'image-elements',
'link-elements',
'meta-elements',
'script-elements',
'iframe-elements',
... // 省略
],
}],
... // 省略
}
2、上述每一个gatherer都有与之对应的实名文件,且都继承自相同的父类Gatherer,Gatherer中定义了三个模版方法,子类只需实现关心的模版方法即可。
// 父类Gatherer
class Gatherer {
// 导航到页面之前
beforePass(passContext) { }
// 在页面loaded后
pass(passContext){ }
// 在页面加载完毕,且trace信息收集完毕后
afterPass(passContext, loadData) { }
}
以名叫RuntimeExceptions的gatherer为例:
const Gatherer = require('./gatherer.js');
class RuntimeExceptions extends Gatherer {
constructor() {
super();
/** @type {Array<LH.Crdp.Runtime.ExceptionThrownEvent>} */
this._exceptions = [];
this._onRuntimeExceptionThrown = this.onRuntimeExceptionThrown.bind(this);
}
/**
* @param {LH.Crdp.Runtime.ExceptionThrownEvent} entry
*/
onRuntimeExceptionThrown(entry) {
this._exceptions.push(entry);
}
/**
* @param {LH.Gatherer.PassContext} passContext
*/
beforePass(passContext) {
const driver = passContext.driver;
driver.on('Runtime.exceptionThrown', this._onRuntimeExceptionThrown);
}
/**
* @param {LH.Gatherer.PassContext} passContext
* @return {Promise<LH.Artifacts['RuntimeExceptions']>}
*/
async afterPass(passContext) {
await passContext.driver.off('Runtime.exceptionThrown', this._onRuntimeExceptionThrown);
return this._exceptions;
}
}
module.exports = RuntimeExceptions;
3、当 pass 中定义的所有 gatherers 运行完后,就会生成一个中间产物 artifacts,此后 Lighthouse 就可以断开与浏览器的连接,只使用 artifacts 进行后续的分析。
Audits
作用:对中间产物artifacts进行加工(对artifacts进行分析计算,得出相关的评分与详情)
原理:每个audit都会继承自一个父类Audit,通过该父类中的方法拿到所需的artifacts项并基于此来计算本项audit的得分与详情
1、配置audits
{
audits: [
'first-meaningful-paint',
'first-cpu-idle',
'byte-efficiency/uses-optimized-images',
]
}
2、父类中有两个重要的方法必须实现:meta和audit
以content-width这个audit为例:
class ContentWidth extends Audit {
//对该 audit 进行描述,并声明所需的artifacts
static get meta() {
return {
id: 'content-width',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.failureTitle),
description: str_(UIStrings.description),
requiredArtifacts: ['ViewportDimensions', 'TestedAsMobileDevice'],
};
}
// 拿到所需的artifacts,并基于此计算出本项audit的得分与详情
static audit(artifacts) {
const IsMobile = artifacts.TestedAsMobileDevice;
const viewportWidth = artifacts.ViewportDimensions.innerWidth;
const windowWidth = artifacts.ViewportDimensions.outerWidth;
const widthsMatch = viewportWidth === windowWidth;
if (!IsMobile) {
return {
score: 1,
notApplicable: true,
};
}
let explanation = '';
if (!widthsMatch) {
explanation = str_(UIStrings.explanation, {
innerWidth: artifacts.ViewportDimensions.innerWidth,
outerWidth: artifacts.ViewportDimensions.outerWidth
});
}
return {
score: Number(widthsMatch),
explanation,
};
}
}
3、当运行完配置文件中定义的所有审计项后,就得到了每个审计项的评分与详情,后续就进入 Report 模块
Categoties
作用:生成最终报告(对中间产物artifacts进行最后的分析计算,得出performance评分并进行布局样式等的处理)
原理:通过配置项或默认属性来对分数进行加权计算、分数并呈现
1、通过设置categories的performance字段来对report进行配置
{
categories: {
performance: {
title: 'Performance',
description: 'This category judges your performance',
auditRefs: [
{id: 'first-meaningful-paint', weight: 2, group: 'metrics'},
{id: 'first-cpu-idle', weight: 3, group: 'metrics'},
{id: 'interactive', weight: 5, group: 'metrics'},
],
},
},
}
四、配置
详细配置请参阅:https://github.com/GoogleChrome/lighthouse/blob/master/docs/configuration.md
lighthouse.config.js 文件
module.exports = {
extends: 'lighthouse:default',
settings: {}, // driver模块的相关设置
passes: {}, // gatherer模块的相关设置
audits: {}, // audit模块的相关设置
categories:{},// categoties模块的相关设置
}
自定义gatherer、audit和report模块
https://github.com/GoogleChrome/lighthouse/blob/master/docs/recipes/custom-audit/custom-config.js
三种限速方式
1.simulated
模拟限速(加载页面时不进行限速,加载完页面后,模拟计算出在限速条件下的性能指标值)
可以在较快的速度下地完成审计并有相似的测试精度
2.devtools
即通过 DevTools 进行限速,页面是在一个真实受限的网络与降速 CPU 条件下加载的
(通过driver模块发送对应领域的指令给 Chrome 浏览器实现)
/**
* @param {Driver} driver
* @param {Required<LH.ThrottlingSettings>} throttlingSettings
* @return {Promise<void>}
*/
function enableCPUThrottling(driver, throttlingSettings) {
const rate = throttlingSettings.cpuSlowdownMultiplier;
return driver.sendCommand('Emulation.setCPUThrottlingRate', {rate});
}
/**
* @param {Driver} driver
* @param {Required<LH.ThrottlingSettings>} throttlingSettings
* @return {Promise<void>}
*/
function enableNetworkThrottling(driver, throttlingSettings) {
/** @type {LH.Crdp.Network.EmulateNetworkConditionsRequest} */
const conditions = {
offline: false,
latency: throttlingSettings.requestLatencyMs || 0,
downloadThroughput: throttlingSettings.downloadThroughputKbps || 0,
uploadThroughput: throttlingSettings.uploadThroughputKbps || 0,
};
// DevTools expects throughput in bytes per second rather than kbps
conditions.downloadThroughput = Math.floor(conditions.downloadThroughput * 1024 / 8);
conditions.uploadThroughput = Math.floor(conditions.uploadThroughput * 1024 / 8);
return driver.sendCommand('Network.emulateNetworkConditions', conditions);
}
3.no throtting
Lighthouse 不进行额外的限速,通常在不进行性能测试、或开发者自行对宿主机进行限速时使用该项
token / authentication
Testing a site with authentication
五、指标说明
Performance(性能,6项统计)
-
LCP(最大内容渲染时间)
LCP是一个页面加载时长的技术指标,用于表示当前页面中最重要/占比最大的内容显示出来的时间点。不同于First Contentful Paint,FCP代表的是第一次页面内容渲染的世界点,LCP是FCP的一个重要的补充,它可以代表当前页面主要内容展示的时间。LCP低于2.5s则表示页面加载速度优良。 -
TBT(初始渲染和页面交互完成的总时间)
TBT是一个衡量用户事件响应的指标。TBT会统计在FCP和TTI时间之间,主线程被阻塞的时间总和。当主线程被阻塞超过50ms导致用户事件无法响应,这样的阻塞时长就会被统计到TBT中。TBT越小说明页面能够更好的快速响应用户事件。 -
FCP(主内容初始渲染时间)
第一次内容丰富的绘画(FCP)指标衡量了从页面开始加载到页面内容的任何部分呈现在屏幕上的时间。对于该指标,"内容"指的是文本、图像(包括背景图像)、svg元素或非白色canvas元素。 -
SI(速度指数)
速度指数衡量的是内容在页面加载过程中的视觉显示速度。Lighthouse首先会在浏览器中捕获一段页面加载的视频,并计算出各帧之间的视觉进度。然后,Lighthouse使用Speedline Node.js模块来生成速度指数得分。 -
TTI(页面交互时间)
-
CLS(累计布局变更/累计视觉变更)
CLS是一个衡量页面内容是否稳定的指标,CLS会将页面加载过程中非预期的页面布局的累积变动。CLS的分数越低,表明页面的布局稳定性越高,通常低于0.1表示页面稳定性良好。
参考说明
部分内容来自官方和网络,不仅限于lighthouse官方网站
原创文章首发认准 软件测试微课堂