<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          火爆的“網(wǎng)抑云”音樂(lè)是如何實(shí)踐性能監(jiān)控

          共 11542字,需瀏覽 24分鐘

           ·

          2020-12-17 13:53

          你的關(guān)注意義重大!

          作者:kkdev163

          https://github.com/x-orpheus

          前言

          云音樂(lè)前端性能監(jiān)控平臺(tái),底層使用了 Lighthouse 進(jìn)行審計(jì)評(píng)分,在實(shí)踐過(guò)程中我們積累了一些 Lighthouse 內(nèi)部實(shí)現(xiàn)的研究經(jīng)驗(yàn),希望通過(guò)這篇文章可以分享給各位讀者。

          本篇文章基于 Lighthouse 5.2.0 版本,介紹了 Lighthouse 的測(cè)試流程、架構(gòu)模塊實(shí)現(xiàn)、性能指標(biāo)的計(jì)算等。通過(guò)這篇文章,讀者可以了解到 Lighthouse 是如何做自動(dòng)化測(cè)試的、如何在 Lighthouse 的框架上自定義一些審計(jì)項(xiàng)、關(guān)鍵的性能指標(biāo)是如何模擬計(jì)算的。

          本篇文章會(huì)按以下四個(gè)部分展開:

          • Lighthouse 簡(jiǎn)介

          • Lighthouse 測(cè)試流程

          • Lighthouse 模塊實(shí)現(xiàn)

          • Lighthouse 性能指標(biāo)計(jì)算

          Lighthouse 簡(jiǎn)介

          Lighthouse 是一個(gè)開源的自動(dòng)化工具,用于改進(jìn)網(wǎng)絡(luò)應(yīng)用的質(zhì)量。只要為 Lighthouse 提供一個(gè)需要審查的網(wǎng)址,它將針對(duì)此頁(yè)面運(yùn)行一連串的測(cè)試,然后生成一個(gè)有關(guān)頁(yè)面性能的報(bào)告。

          Lighthouse 使用方式

          目前官方提供了4種使用方式:

          • Chrome 開發(fā)者工具(DevTools)

          • Chrome 擴(kuò)展

          • Node CLI

          • Node Module

          以 Chrome 開發(fā)者工具為例,在 Audits 面板下,用戶可以配置測(cè)試平臺(tái)、測(cè)試類目、限速方式等,可以方便快捷地發(fā)起一次測(cè)試。

          image

          Lighthouse 測(cè)試報(bào)告

          測(cè)試結(jié)束后,默認(rèn)會(huì)生成 HTML 格式的報(bào)告,如下圖所示,在報(bào)告中涵蓋了 5 大類別(categories)的測(cè)試評(píng)分:

          image

          每個(gè)類別都包含一系列的審計(jì)項(xiàng)(audit),針對(duì)審計(jì)項(xiàng)的運(yùn)行結(jié)果,Lighthouse 會(huì)給出特定的優(yōu)化建議與診斷結(jié)果幫助開發(fā)者有針對(duì)性地進(jìn)行優(yōu)化。

          本節(jié)簡(jiǎn)要介紹了 Lighthouse 的使用方式與測(cè)試報(bào)告組成,下一節(jié)將介紹 Lighthouse 的測(cè)試流程。

          Lighthouse 測(cè)試流程

          我們以 Node CLI 的方式進(jìn)行測(cè)試,分析 Lighthouse 的測(cè)試流程。

          參考官方文檔,安裝好 CLI 后,輸入如下命令,可以進(jìn)行一次測(cè)試

          lighthouse --only-categories=performance https://google.com

          注:以上命令只進(jìn)行 performance 類別測(cè)試。

          在 CLI 中會(huì)輸出測(cè)試過(guò)程中的日志,截圖顯示如下,在日志中,可以看出測(cè)試大致分為如下幾個(gè)階段:

          image

          通過(guò)輸出的日志,可以畫出 Lighthouse 的測(cè)試流程圖:

          image
          1. Lighthouse 與瀏覽器建立連接。

          2. 測(cè)試的初始化配置與加載待測(cè)試頁(yè)面。

          3. 在頁(yè)面加載過(guò)程中,運(yùn)行一系列的采集器(gatherers),每個(gè)采集器都會(huì)收集自己的目標(biāo)信息,并生成中間產(chǎn)物(artifacts)。

          4. 運(yùn)行一系列的審計(jì)項(xiàng)(audits),每個(gè)審計(jì)項(xiàng)都會(huì)從中間產(chǎn)物(artifacts)中獲取所需的數(shù)據(jù),計(jì)算出各自的評(píng)分。

          5. 基于審計(jì)項(xiàng)的評(píng)分計(jì)算出大類的評(píng)分,匯總生成報(bào)告。

          本節(jié)基于 Lighthouse 的測(cè)試日志,介紹了 Lighthouse 的測(cè)試流程,下節(jié)將介紹流程中的模塊實(shí)現(xiàn)。

          Lighthouse 模塊實(shí)現(xiàn)

          初步了解了基本的測(cè)試流程后,我們?cè)倏聪鹿俜浇o出的 Lighthouse 架構(gòu)圖:

          image

          這張圖中體現(xiàn)了測(cè)試的主要流程,從中也可以圈出 4 個(gè)主要模塊,下文會(huì)對(duì)這幾個(gè)模塊做逐個(gè)講解。

          Driver 模塊

          雙向通信與 DevTools 協(xié)議

          Chrome 瀏覽器在啟動(dòng)的時(shí)候,可以通過(guò)?--remote-debugging-port?參數(shù)設(shè)置遠(yuǎn)程調(diào)試端口,如以下命令可以打開 Chrome 并設(shè)置遠(yuǎn)程調(diào)試端口為9222。

          chrome.exe --remote-debugging-port=9222

          之后就可以使用地址 http://localhost:9222 進(jìn)行遠(yuǎn)程調(diào)試了,比如以下命令可以讓 Chrome 瀏覽器打開一個(gè)新的 Tab。

          curl http://localhost:9222/json/new

          該命令還會(huì)返回此 Tab 的相關(guān)信息,其中需要關(guān)注的是 webSocketDebuggerUrl,這是該 Tab 的 WebSocket 連接地址。

          {
          "id": "29989D...",
          "url": "about:blank",
          "webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/29989D...",
          ...
          }

          Driver 模塊持有 Connection 實(shí)例(負(fù)責(zé)與瀏覽器進(jìn)行通信),該實(shí)例在初始化的時(shí)候,正是通過(guò)調(diào)用遠(yuǎn)程調(diào)試端口的/json/new指令打開一個(gè)新的 Tab,并使用返回的 webSocketDebuggerUrl 與瀏覽器建立 WebSocket 連接,之后就可以進(jìn)行雙向通信。

          1. 新開一個(gè)Tab

          image
          1. 建立 WebSocket 連接

          image

          雙方建立 WebSocket 連接后,必須使用一種數(shù)據(jù)格式協(xié)議進(jìn)行通信,該協(xié)議就是 Chrome DevTools Protocol,此協(xié)議以 JSON 為格式,定義指令的方法名與參數(shù)。

          如下圖所示,發(fā)送 Page.navigate 指令可以讓 Chrome 導(dǎo)航至目標(biāo)頁(yè)面。發(fā)送 Page.captureScreenshot 指令可以讓 Chrome 生成當(dāng)前頁(yè)面的截圖數(shù)據(jù)。

          image

          在該協(xié)議的文檔中,所有的控制指令和事件被劃分至多個(gè)領(lǐng)域(Domains)如 Page、Network 等。打開 Page 領(lǐng)域,可以找到示例指令 Page.navigate 的詳細(xì)說(shuō)明:

          image

          除了 navigate、captureScreenshot 等主動(dòng)調(diào)用的指令外,當(dāng)我們調(diào)用某個(gè)領(lǐng)域的 enable 指令后,后續(xù)就可以接收到該領(lǐng)域推送的通知事件。

          Lighthouse 通過(guò) Chrome DevTools Protocol 定義的主動(dòng)指令與事件通知,就實(shí)現(xiàn)了操控 Chrome 瀏覽器,和感知頁(yè)面加載過(guò)程中的各個(gè)事件。

          日志記錄

          Driver 模塊中的另外2個(gè)重要實(shí)例是 DevtoolsLog、NetworkRecorder,他們用于將瀏覽器發(fā)出的通知事件進(jìn)行結(jié)構(gòu)化的存儲(chǔ)。其中 DevtoolsLog 會(huì)記錄各個(gè)領(lǐng)域的全量日志,NetworkRecorder 只存儲(chǔ)網(wǎng)絡(luò)相關(guān)日志,并會(huì)分析出當(dāng)前網(wǎng)絡(luò)請(qǐng)求狀態(tài)(繁忙、空閑)等。

          image

          存儲(chǔ)的日志信息將在后續(xù)的審計(jì)(Audits)模塊中使用,下文會(huì)繼續(xù)提到他們。

          仿真器(emulation)

          Driver 模塊中最后值得一提的部分是仿真器(emulation),該模塊的作用是模擬測(cè)試設(shè)備,如模擬 移動(dòng)端 / PC 端、屏幕的尺寸,模擬設(shè)備的 UserAgent、Cookie、網(wǎng)絡(luò)限速等。

          這些模擬功能的設(shè)置,也是通過(guò) Connection 模塊向 Chrome 瀏覽器發(fā)送對(duì)應(yīng)領(lǐng)域的操控指令實(shí)現(xiàn)的。

          image

          至此我們分析完了 Driver 模塊的主要組成部分,我們來(lái)簡(jiǎn)單總結(jié)下:負(fù)責(zé)與瀏覽器的雙向通信、記錄事件日志、模擬器的設(shè)置等。

          Gatherer 模塊

          image

          該模塊的一個(gè)重要概念是 pass,官方是這樣定義 pass 的:

          controls how to load the requested URLand what information to gather about the page while loading.

          即控制頁(yè)面如何加載,并決定在頁(yè)面加載過(guò)程中采集哪些信息

          defines basic settings such as how long to wait for the page to load and whether to record a trace file. Additionally a list of gatherers to use is defined per pass. Gatherers can read information from the page to generate artifacts which are later used by audits to provide you with a Lighthouse report.

          即定義頁(yè)面加載等待時(shí)間、是否記錄 trace 文件等配置。每個(gè) pass 還定義了一個(gè) gatherers 列表,gatherers 可以從頁(yè)面中讀取需要的信息并生成一個(gè)中間產(chǎn)物,中間產(chǎn)物將會(huì)用于后續(xù)的審計(jì)分析,并最終生成測(cè)試報(bào)告。

          了解了 pass 的定義,來(lái)看一個(gè)具體的 pass 配置:

          {
          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',
          ... // 省略
          ],
          },
          ... // 省略
          }

          其中的 gatherers 是我們需要關(guān)注的重點(diǎn),每一個(gè) gatherer,在代碼倉(cāng)庫(kù)中都有與之對(duì)應(yīng)的同名實(shí)現(xiàn)文件,并且都繼承自相同的父類 Gatherer,其中定義了三個(gè)模板方法,子類只需實(shí)現(xiàn)關(guān)心的模板方法即可。

          class Gatherer {
          // 在頁(yè)面導(dǎo)航前
          beforePass(passContext) { }

          // 在頁(yè)面loaded后
          pass(passContext){ }

          // 在頁(yè)面加載完畢,且trace信息收集完畢后
          afterPass(passContext, loadData) { }
          }

          以一個(gè)比較簡(jiǎn)單的 Gatherer 具體實(shí)現(xiàn) RuntimeExceptions 為例,該實(shí)例實(shí)現(xiàn)了 beforePass 、afterPass 兩個(gè)生命周期模板方法,其中 driver.on 正是通過(guò)上文介紹的 Driver 模塊實(shí)現(xiàn)的事件監(jiān)聽(tīng)。

          const Gatherer = require('./gatherer.js');

          class RuntimeExceptions extends Gatherer {
          constructor() {
          super();
          this._exceptions = [];
          this._onRuntimeExceptionThrown = this.onRuntimeExceptionThrown.bind(this);
          }

          onRuntimeExceptionThrown(entry) {
          this._exceptions.push(entry);
          }

          // 在頁(yè)面導(dǎo)航前,注冊(cè)事件監(jiān)聽(tīng)器,采集錯(cuò)誤信息
          beforePass(passContext) {
          const driver = passContext.driver;
          driver.on('Runtime.exceptionThrown', this._onRuntimeExceptionThrown);
          }

          // 在頁(yè)面加載完畢后,解除事件監(jiān)聽(tīng)
          async afterPass(passContext) {
          await passContext.driver.off('Runtime.exceptionThrown', this._onRuntimeExceptionThrown);
          return this._exceptions;
          }
          }

          有了這個(gè)參考示例,我們也可以輕松地寫一個(gè)自定義的 Gatherer,比如用于采集頁(yè)面標(biāo)題的 gatherer:

          const Gatherer = require('./gatherer.js');

          function getPageTitle() {
          return document.title;
          }

          class PageTitle extends Gatherer {

          afterPass(passContext) {
          return passContext.driver.evaluateAsync(`(${getPageTitle.toString()}())`);
          }
          }

          我們只重寫了 afterPass 方法,在該生命中期中,將腳本通過(guò) driver 模塊發(fā)送給瀏覽器執(zhí)行,并獲取到執(zhí)行結(jié)果。

          當(dāng) pass 中定義的所有 gatherers 運(yùn)行完后,就會(huì)生成一個(gè)中間產(chǎn)物 artifacts,此后 Lighthouse 就可以斷開與瀏覽器的連接,只使用 artifacts 進(jìn)行后續(xù)的分析。

          總結(jié)下 Gatherer 模塊,該模塊會(huì)通過(guò) pass 這個(gè)配置,定義頁(yè)面如何加載,并運(yùn)行配置的所有 gatherers 來(lái)采集頁(yè)面加載過(guò)程中的信息,并生成中間產(chǎn)物 artifacts。有了 artifacts,就可以進(jìn)入下一步的 Audits 模塊。

          Audits 模塊

          與 gatherers 類似,在配置文件中也會(huì)定義需要運(yùn)行的 audits,每一個(gè) audits 也都有與之對(duì)應(yīng)的同名實(shí)現(xiàn)文件。

          {
          audits: [
          'errors-in-console',
          'metrics/first-contentful-paint',
          'metrics/first-meaningful-paint',
          'metrics/speed-index',
          'metrics/first-cpu-idle',
          'metrics/interactive',
          'screenshot-thumbnails',
          'final-screenshot',
          // 省略
          ],
          // 省略
          }

          我們還是從最為簡(jiǎn)單的 errors-in-console 入手,了解下一個(gè) audit 是如何實(shí)現(xiàn)的。

          在每個(gè) audit 中都會(huì)定義一個(gè)靜態(tài)方法meta(),對(duì)該 audit 進(jìn)行描述,并聲明所需的 artifacts,ErrorLogs 這項(xiàng) audit 就聲明了其需要上文提到的 RuntimeExceptions 所生成的中間產(chǎn)物。

          class ErrorLogs extends Audit {
          static get meta() {
          return {
          id: 'errors-in-console',
          title: str_(UIStrings.title),
          failureTitle: str_(UIStrings.failureTitle),
          description: str_(UIStrings.description),
          requiredArtifacts: ['ConsoleMessages', 'RuntimeExceptions'],
          };
          }
          }

          Audit 實(shí)例需要實(shí)現(xiàn)的另一個(gè)模板方法是audit(),在該方法中可以拿到所需的中間產(chǎn)物,并基于中間產(chǎn)物計(jì)算出本項(xiàng) audit 的得分與詳情。

          static audit(artifacts) {
          // 獲取所需的中間產(chǎn)物
          const runtimeExceptions = artifacts.RuntimeExceptions;

          // 數(shù)據(jù)的過(guò)濾與轉(zhuǎn)換
          const runtimeExRows =
          runtimeExceptions.filter(entry => entry.exceptionDetails !== undefined)
          .map(entry => {
          const description = entry.exceptionDetails.exception ?
          entry.exceptionDetails.exception.description : entry.exceptionDetails.text;

          return {
          source: 'Runtime.exception',
          description,
          url: entry.exceptionDetails.url,
          };
          });

          // 省略表格詳情生成代碼
          ...

          // 計(jì)算出審計(jì)項(xiàng)的得分
          const numErrors = tableRows.length;
          return {
          score: Number(numErrors === 0),
          numericValue: numErrors,
          details,
          };
          }

          有了上面的示例,我們就可以參照實(shí)現(xiàn)一個(gè)自定義審計(jì)項(xiàng),如審計(jì)頁(yè)面標(biāo)題:

          class PageTitle extends Audit {
          static get meta() {
          return {
          id: 'page-title',
          title: 'title of page document',
          failureTitle: 'Does not have page title',
          description: 'This audit get document.title when page loaded',
          requiredArtifacts: ['PageTitle'],
          };
          }

          static audit(artifacts) {
          return {
          score: artifacts.PageTitle ? 1 : 0,
          displayValue: artifacts.PageTitle || 'none'
          };
          }
          }

          當(dāng)運(yùn)行完配置文件中定義的所有審計(jì)項(xiàng)后,就得到了每個(gè)審計(jì)項(xiàng)的評(píng)分與詳情,后續(xù)就進(jìn)入 Report 模塊。

          Report 模塊

          在配置文件中,會(huì)定義每個(gè)測(cè)試類別所需的審計(jì)項(xiàng),以及每個(gè)審計(jì)項(xiàng)所占的權(quán)重。如下所示的為性能(performance)這項(xiàng)測(cè)試類別所需的審計(jì)項(xiàng):

          {
          'performance': {
          title: str_(UIStrings.performanceCategoryTitle),
          auditRefs: [
          {id: 'first-contentful-paint', weight: 3, group: 'metrics'},
          {id: 'first-meaningful-paint', weight: 1, group: 'metrics'},
          {id: 'speed-index', weight: 4, group: 'metrics'},
          {id: 'interactive', weight: 5, group: 'metrics'},
          {id: 'first-cpu-idle', weight: 2, group: 'metrics'},
          {id: 'max-potential-fid', weight: 0, group: 'metrics'},
          // 省略
          ]
          },
          }

          在最終匯總階段,Lighthouse 會(huì)基于該配置文件以及上一個(gè)環(huán)節(jié)中計(jì)算出的每個(gè)審計(jì)項(xiàng)的評(píng)分,加權(quán)計(jì)算出 performance 的評(píng)分。并基于每個(gè)審計(jì)項(xiàng)的評(píng)分與種類,將審計(jì)項(xiàng)劃分為通過(guò)與不通過(guò),對(duì)于不通過(guò)的審計(jì)項(xiàng)會(huì)給出詳細(xì)的測(cè)試詳情與優(yōu)化指引。

          FCP 等性能指標(biāo)審計(jì)項(xiàng)的實(shí)現(xiàn)

          在上文介紹整體測(cè)試流程的過(guò)程中,我選擇了最為簡(jiǎn)單的審計(jì)項(xiàng)展開介紹,本節(jié)會(huì)挑選大家更為關(guān)心的性能審計(jì)指標(biāo)如 FCP 展開介紹。

          FCP(First Contentful Paint) 首次內(nèi)容繪制時(shí)間,是從頁(yè)面導(dǎo)航開始,到瀏覽器從 DOM 中渲染出首個(gè)內(nèi)容的時(shí)間。

          限速模擬

          由于頁(yè)面性能受宿主機(jī)網(wǎng)絡(luò)與 CPU 頻率等參數(shù)的影響較大,Lighthouse 提供了三種方式供模擬較差的宿主機(jī)環(huán)境,其背后的邏輯是,如果頁(yè)面能夠在較差的環(huán)境下達(dá)到一個(gè)較好的測(cè)試分?jǐn)?shù)、那么大部分用戶對(duì)頁(yè)面的直觀感受都會(huì)較好。

          在 Chrome Devtools 的 Audits 面板中,可以看到三種限速方式:

          image

          上圖配置項(xiàng)分別對(duì)應(yīng)下面三種限速方式的介紹

          simulated

          Throttling is simulated, resulting in faster auditruns with similar measurement accuracy

          即限速是模擬的(加載頁(yè)面時(shí)不進(jìn)行限速,加載完頁(yè)面后,模擬計(jì)算出在限速條件下的性能指標(biāo)值),所以可以在較快的速度下地完成審計(jì)并有相似的測(cè)試精度。

          devtools

          Typical DevTools throttling, with actual traffic shapingand CPU slowdown applied

          即通過(guò) DevTools 進(jìn)行限速,頁(yè)面是在一個(gè)真實(shí)受限的網(wǎng)絡(luò)與降速 CPU 條件下加載的。

          no throttling

          No network or CPU throttling used.(Useful when not evaluating performance)

          即 Lighthouse 不進(jìn)行額外的限速,通常在不進(jìn)行性能測(cè)試、或開發(fā)者自行對(duì)宿主機(jī)進(jìn)行限速時(shí)使用該項(xiàng)。

          在三種限速方式中,Lighthouse 真正對(duì)網(wǎng)絡(luò)與 CPU 進(jìn)行限速的只有 devtools 這種限速方式,實(shí)現(xiàn)的方式是通過(guò)上文提到的 Driver 模塊發(fā)送對(duì)應(yīng)領(lǐng)域的指令給 Chrome 瀏覽器:

          // 開啟CPU限速
          function enableCPUThrottling(driver, throttlingSettings) {
          const rate = throttlingSettings.cpuSlowdownMultiplier;
          return driver.sendCommand('Emulation.setCPUThrottlingRate', {rate});
          }

          // 開啟網(wǎng)絡(luò)限速
          function enableNetworkThrottling(driver, throttlingSettings) {
          // 省略部分代碼
          return driver.sendCommand('Network.emulateNetworkConditions', conditions);
          }

          Trace 信息

          在上文介紹 pass 時(shí),我們提到其中有一個(gè)參數(shù)用來(lái)控制是否收集 Trace 信息,Trace 信息是什么?它又有什么用呢?

          其實(shí)我們大部分同學(xué)都已經(jīng)接觸過(guò) Trace 信息,它的可視化展示就在 Chrome devtools 中 Performance 面板:

          image

          在這個(gè)可視化面板中,可以看到頁(yè)面加載過(guò)程中關(guān)鍵渲染節(jié)點(diǎn) FP、FCP、FMP 等,并可以看到主線程進(jìn)行的 Parse HTML、Layout、JS 的執(zhí)行依賴情況等。

          當(dāng) pass 中配置了開啟收集 Trace 信息時(shí),Lighthouse 在頁(yè)面加載完畢后,就可以拿到完整的 Trace 信息, 從中可以知道頁(yè)面加載時(shí)的 FCP、FMP 等關(guān)鍵渲染節(jié)點(diǎn)。

          FCP 的模擬計(jì)算

          當(dāng)使用 devtools、no throttling 這兩種方式進(jìn)行限速時(shí),由于頁(yè)面就是在真實(shí)受限的網(wǎng)絡(luò)條件下加載的,Trace 信息中給出的 FCP 值就是限速條件下的 FCP 值,所以 Lighthouse 無(wú)需進(jìn)行任何額外的加工處理。

          但在 simulated 這種限速方式下,頁(yè)面是在沒(méi)有限速的條件下加載,所以 Trace 中的 FCP 是不限速時(shí)的 FCP,Lighthouse 需要通過(guò)模擬計(jì)算的方式,得出在給定限速條件下的 FCP 估算值。接下來(lái)我們重點(diǎn)介紹 simulated 這種模擬方式下,F(xiàn)CP 的計(jì)算。

          上文我們提到在 Driver 模塊中有個(gè) NetworkRecorder,這個(gè)模塊會(huì)記錄頁(yè)面加載過(guò)程中的所有網(wǎng)絡(luò)請(qǐng)求詳情,Lighthouse 會(huì)為每個(gè)有效的網(wǎng)絡(luò)請(qǐng)求事件建立一個(gè)對(duì)應(yīng)的 Network Node 節(jié)點(diǎn)。

          Trace 信息中也會(huì)記錄頁(yè)面加載過(guò)程中 CPU 執(zhí)行事件,Lighthouse 會(huì)為每個(gè)有效的 CPU 事件建立一個(gè)對(duì)應(yīng)的 CPU Node 節(jié)點(diǎn)。

          image

          緊接著,Lighthouse 會(huì)從 Network 請(qǐng)求節(jié)點(diǎn)中找出根節(jié)點(diǎn)(請(qǐng)求 Document 的節(jié)點(diǎn)),并根據(jù)節(jié)點(diǎn)依賴算法,建立起 CPU 節(jié)點(diǎn)與 Network 節(jié)點(diǎn)之間的依賴,最終生成頁(yè)面加載依賴的有向無(wú)環(huán)圖:

          image

          建立了頁(yè)面加載所需的完整依賴圖后,Lighthouse 會(huì)結(jié)合 Trace 信息中的 FCP 事件時(shí)間,分析出頁(yè)面 FCP 所需的的依賴圖:

          image

          有了頁(yè)面 FCP 所需的依賴圖后,Lighthouse 模擬計(jì)算出,在限速條件下,請(qǐng)求依賴圖中的資源,執(zhí)行依賴圖中的 CPU 事件,所需的耗時(shí),以此得出在特定限速條件下的 FCP 估算值。

          image

          模擬 HTTP 請(qǐng)求

          Lighthouse 通過(guò)模擬 HTTP 的方式,計(jì)算出在特定網(wǎng)絡(luò)條件下的資源下載耗時(shí),而不是真實(shí)地發(fā)起網(wǎng)絡(luò)請(qǐng)求,我們來(lái)看下 Lighthouse 是如何做模擬的。

          image
          image

          在上述的代碼中,我們看到 Lighthouse 完全是通過(guò)模擬 HTTP 的方式,計(jì)算出了一個(gè)資源在特定網(wǎng)絡(luò)條件下,所需要的耗時(shí)。并且這個(gè)模擬考慮了 HTTP2 多路復(fù)用技術(shù)、 請(qǐng)求是否 KeepAlive、TCP 三次握手、擁塞窗口等細(xì)節(jié)。

          我們用一張圖來(lái)總結(jié)和對(duì)比一下,兩種限速方式計(jì)算 FCP 的流程差異:

          image

          可以看出兩種限速方式,都是以 DevTools 給出的 Trace 信息為基礎(chǔ),在 Simulate 限速方式下,在拿到 FCP 值后,還需要模擬計(jì)算在限速條件下的估算值。在 Simulate 限速方式下,其他性能指標(biāo)如 FMP、SpeedIndex 等也是通過(guò)類似的方式進(jìn)行模擬計(jì)算,至此我們分析完了 Lighthouse 性能指標(biāo) FCP 審計(jì)項(xiàng)的實(shí)現(xiàn)原理。

          總結(jié)

          本篇文章為大家簡(jiǎn)要介紹了 Lighthouse、并分析了 Lighthouse 的測(cè)試流程與主要的模塊實(shí)現(xiàn),最后向大家介紹了關(guān)鍵性能指標(biāo) FCP 的模擬計(jì)算方式,希望能對(duì)大家有所收獲。文末會(huì)貼出文章中提到的模塊的源碼導(dǎo)航,有興趣的朋友可以看下,歡迎大家進(jìn)行交流。

          —————END—————



          喜歡本文的朋友,歡迎關(guān)注公眾號(hào)?程序員哆啦A夢(mèng),收看更多精彩內(nèi)容

          點(diǎn)個(gè)[在看],是對(duì)小達(dá)最大的支持!


          如果覺(jué)得這篇文章還不錯(cuò),來(lái)個(gè)【分享、點(diǎn)贊、在看】三連吧,讓更多的人也看到~

          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  看美女操逼视频 | 漂亮一区二区三区大学生 | 国产精品久久欠久久久久久九秃 | 欧美三级黄 | www.欧美成人 |