建設(shè)網(wǎng)站要做的工作總結(jié)網(wǎng)頁模板免費(fèi)下載網(wǎng)站
Lighthouse簡介
Lighthouse是一個(gè)開源的自動(dòng)化性能測試工具,我們可以使用該功能檢測我們的頁面存在那些性能方面的問題,并會(huì)生成一個(gè)詳細(xì)的性能報(bào)告來幫助我們來優(yōu)化頁面
使用方式
LH一共有四種使用方式
- Chrome開發(fā)者工具
- Chrome擴(kuò)展
- Node 命令行
- Node module
前兩種方式是在用戶瀏覽器端直接運(yùn)行,以開發(fā)者工具為例,我們打開控制臺(tái),可以看到有一個(gè)Lighthouse的選項(xiàng),點(diǎn)擊之后,就可以直接檢測當(dāng)前頁面的性能了。
這里有幾個(gè)選項(xiàng),一個(gè)是模式,一般我們選擇默認(rèn)模式即可。一個(gè)是設(shè)備,可以模擬移動(dòng)端設(shè)備或者桌面設(shè)備還有一個(gè)是檢測的類別。確定選項(xiàng)之后點(diǎn)擊分析網(wǎng)頁加載情況即可開始對當(dāng)前頁面進(jìn)行性能分析。以京東的首頁為例經(jīng)過一段時(shí)間的檢測后會(huì)生成如下的報(bào)告
我們可以看到報(bào)告中會(huì)審計(jì)各種各樣的指標(biāo),其中時(shí)間維度比較重要的就是下面6個(gè)指標(biāo):
- SI
- FCP
- TTI
- TBT
- LCP
- CLS
在此之后還有一些優(yōu)化的建議,比如圖片的預(yù)加載,移除阻塞渲染的資源,和減少未使用的js加載等等…
后兩種模式,我們可以將lighthouse運(yùn)行在自己的服務(wù)上,這樣結(jié)合一些自動(dòng)化的手段,就無需用戶自己在瀏覽器端主動(dòng)進(jìn)行檢測了,而是可以在需要的時(shí)候(比如開發(fā)的頁面上線前在測試階段)可以主動(dòng)在我們的服務(wù)中對該頁面進(jìn)行性能的檢測,確保我們上線的頁面會(huì)有一個(gè)比較好的性能表現(xiàn),下面會(huì)重點(diǎn)以Node module的方式來介紹使用
整體架構(gòu)
我們看github上官方文檔對lighthouse的整體架構(gòu)設(shè)計(jì)有這么一張圖:
Puppeteer & Chrome
由上圖左下側(cè)我們可以看到,lighthouse是通過Driver模塊和Puppeteer(一個(gè) Node 庫,它提供了一個(gè)高級 API 來通過 DevTools 協(xié)議控制 Chromium 或 Chrome)來控制瀏覽器,我們可以通過Puppeteer來模擬用戶對瀏覽器的各種操作,比如點(diǎn)擊元素,滾動(dòng)頁面,鍵盤操作。一個(gè)常見的場景就是我們自己的產(chǎn)品使用lighthouse進(jìn)行檢測的時(shí)候,往往需要用戶先登錄,此時(shí)我們就可以使用Puppeteer來幫助我們先模擬用戶登錄,登錄之后,利用Cookie的同源策略再次檢測我們的頁面就可以了。
Gatherers
顧名思義如翻譯之后的意思,這是一個(gè)收集器。需要在配置文件中定義需要運(yùn)行的Gatherer,每一個(gè)Gatherer都有一個(gè)在配置文件中同名的文件來實(shí)現(xiàn)收集器的功能。以達(dá)到在審計(jì)一個(gè)頁面的時(shí)候需要收集這個(gè)頁面的各種指標(biāo)數(shù)據(jù),收集這些指標(biāo)數(shù)據(jù)就是Gatherers模塊完成的。比如在lighthouse內(nèi)置收集器中有這些文件都是gatherer。
這些gatherer都需要繼承一個(gè)標(biāo)準(zhǔn)的Gather來實(shí)現(xiàn)功能,在后面我們演示自定義Gatherer時(shí)也需要繼承這個(gè)基類
beforepass、pass、afterpass
在這個(gè)里面有個(gè)很重要的概念就是pass,包含三個(gè)階段即:beforepass、pass、afterpass。來控制頁面是如何加載,以及在加載過程中采集那些數(shù)據(jù)。
關(guān)于beforepass、pass、afterpass這三個(gè)的區(qū)別從名稱上也能看出,一個(gè)導(dǎo)航到目標(biāo)頁面之前,一個(gè)是目標(biāo)頁面加載之后,一個(gè)是目標(biāo)頁面加載后并且所有的pass都執(zhí)行完之后。我們可以直接看lighthouse源碼部分
Audits
我們從架構(gòu)圖中可以看到,Gathering模塊運(yùn)行之后會(huì)生成一個(gè)artifacts,其實(shí)就是一些采集的數(shù)據(jù),這些數(shù)據(jù)進(jìn)行一些列的計(jì)算之后再傳遞給Audits,由Audits來對這些數(shù)據(jù)進(jìn)行進(jìn)一步的審計(jì),計(jì)算出每一項(xiàng)的具體得分,為生成的報(bào)告提供數(shù)據(jù)。
與gatherers類似,在配置文件中也會(huì)定義需要運(yùn)行的audit。每一個(gè)audit也都有一個(gè)與之對應(yīng)的同名文件來實(shí)現(xiàn)具體的審計(jì)功能。
每個(gè)audit都會(huì)實(shí)現(xiàn)一個(gè)靜態(tài)的meta()方法和一個(gè)靜態(tài)的audit()方法。如果沒有實(shí)現(xiàn)這兩個(gè)方法的話就會(huì)拋錯(cuò)哦
Lighthouse Audit源碼
meta
Audits中的meta是對當(dāng)前Audit的一些描述。一共有如下一些字段
其中比較重要的一個(gè)是ID,這個(gè)需要和傳入的配置中的auditRefs數(shù)組中的ID相對應(yīng),否則找不到。另一個(gè)就是requiredArtifacts這是一個(gè)數(shù)組,表示該Audit需要哪些gatherer模塊
audit
lighthouse中的audit函數(shù)如下:
/**** @param {LH.Artifacts} artifacts* @param {LH.Audit.Context} context* @return {LH.Audit.Product|Promise<LH.Audit.Product>}*/static audit(artifacts, context) {throw new Error('audit() method must be overriden');}
這個(gè)函數(shù)接受兩個(gè)參數(shù)一個(gè)是制品,即gatherer采集的那些數(shù)據(jù),掛在artifacts.ResourceGatherer屬性中,以及context當(dāng)前的上下文。
我們一般會(huì)在audit中由傳遞過來采集的數(shù)據(jù)和該指標(biāo)的權(quán)重來計(jì)算出該項(xiàng)指標(biāo)具體的得分,最終會(huì)返回一個(gè)對象。我們可以看一下源碼中的定義,看看返回對象的數(shù)據(jù)形狀是什么樣的。
首先是audit函數(shù)說明上,會(huì)return 一個(gè)LH.Audit.Product的東西。我們可以點(diǎn)擊去看看這是個(gè)啥。
源碼部分:
/** The shared properties of an Audit.Product whether it has a numericValue or not. We want to enforce `numericUnit` accompanying `numericValue` whenever it is set, so the final Audit.Product type is a discriminated union on `'numericValue' in audit`*/interface ProductBase {/** The scored value of the audit, provided in the range `0-1`, or null if `scoreDisplayMode` indicates not scored. */score: number | null;/** The i18n'd string value that the audit wishes to display for its results. This value is not necessarily the string version of the `numericValue`. */displayValue?: string | IcuMessage;/** An explanation of why the audit failed on the test page. */explanation?: string | IcuMessage;/** Error message from any exception thrown while running this audit. */errorMessage?: string | IcuMessage;warnings?: Array<string | IcuMessage>;/** Overrides scoreDisplayMode with notApplicable if set to true */notApplicable?: boolean;/** Extra information about the page provided by some types of audits, in one of several possible forms that can be rendered in the HTML report. */details?: AuditDetails;/** If an audit encounters unusual execution circumstances, strings can be put in this optional array to add top-level warnings to the LHR. */runWarnings?: Array<IcuMessage>;}/** The Audit.Product type for audits that do not return a `numericValue`. */interface NonNumericProduct extends ProductBase {numericValue?: never;}/** The Audit.Product type for audits that do return a `numericValue`. */interface NumericProduct extends ProductBase {/** A numeric value that has a meaning specific to the audit, e.g. the number of nodes in the DOM or the timestamp of a specific load event. More information can be found in the audit details, if present. */numericValue: number;/** The unit of `numericValue`, used when the consumer wishes to convert numericValue to a display string. A superset of https://tc39.es/proposal-unified-intl-numberformat/section6/locales-currencies-tz_proposed_out.html#sec-issanctionedsimpleunitidentifier */numericUnit: 'byte'|'millisecond'|'element'|'unitless';}/** Type returned by Audit.audit(). Only score is required. */type Product = NonNumericProduct | NumericProduct;
具體的字段名稱的含義可以看上面的說明,吐槽一下,lighthouse的使用文檔寫的真是一般,但代碼中的注釋寫的倒是還闊以。
Audit函數(shù)字段說明
Lighthouse Report
由架構(gòu)圖我們可以看到,由Audits審計(jì)之后會(huì)生成一個(gè)LHR.json的文件,這個(gè)文件就是最終的數(shù)據(jù)報(bào)告了。然后會(huì)基于此由report模塊來對這些數(shù)據(jù)進(jìn)行渲染生成一個(gè)html文件
使用方式
官網(wǎng)的demo
整體代碼如下:
/*** 官網(wǎng)示例* https://github.com/GoogleChrome/lighthouse/blob/main/docs/readme.md#using-programmatically**/
import fs from 'fs'
import lighthouse from 'lighthouse'
import chromeLauncher from 'chrome-launcher'
// https://github.com/GoogleChrome/lighthouse/discussions/12058
import desktopConfig from 'lighthouse/lighthouse-core/config/desktop-config.js'// const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] })
const chrome = await chromeLauncher.launch()
const options = { logLevel: 'info', output: 'html', onlyCategories: ['performance'], port: chrome.port }
const runnerResult = await lighthouse('https://www.jd.com/', options, desktopConfig)// `.report` is the HTML report as a string
const reportHtml = runnerResult.report
fs.writeFileSync('lhreport.html', reportHtml)// `.lhr` is the Lighthouse Result as a JS object
console.log('Report is done for', runnerResult.lhr.finalDisplayedUrl)
console.log('Performance score was', runnerResult.lhr.categories.performance.score * 100)await chrome.kill()
在運(yùn)行的時(shí)候,我們可以將{ chromeFlags: [‘–headless’] }參數(shù)去除,不使用無頭模式,這樣我們可以觀察整個(gè)程序的執(zhí)行流程。這里也稍作修改一下,在Node module中默認(rèn)是移動(dòng)端模式,我們這里修改成PC端模式,需要對lighthouse傳入第三個(gè)參數(shù)。第三個(gè)參數(shù)就是模擬的PC端的桌面模式。這里還是以京東首頁為例子。效果如下:
在項(xiàng)目中會(huì)生成一個(gè)lhreport.html報(bào)告文件
官網(wǎng)的demo是比較簡單的,但實(shí)際我們在應(yīng)用的時(shí)候,場景會(huì)比較復(fù)雜,比如我們大多數(shù)的產(chǎn)品都需要登錄,如果不登錄就沒法訪問頁面,那就沒法檢測了。后面會(huì)接著分享,如果使用puppeteer+lighthouse來解決這個(gè)場景以及自定義gatherers 和audits。
參考資料
- lighthouse 架構(gòu)圖
- SI指標(biāo)說明
- FCP指標(biāo)說明
- TTI指標(biāo)說明
- TBT指標(biāo)說明
- LCP指標(biāo)說明
- CLS指標(biāo)說明
- Puppeteer 中文文檔
- Gather部分源碼
- Lighthouse Audit源碼
- Audit函數(shù)字段說明
- Node module使用