Эта статья написана фронтенд-инженером NetEase Cloud Music kkdev163.личный блогТакже записаны некоторые практические статьи в области фронтенд-мониторинга.
предисловие
Платформа мониторинга производительности внешнего интерфейса облачной музыки использует Lighthouse для оценки аудита на нижнем уровне.В процессе практики мы накопили некоторый опыт исследований внутренней реализации Lighthouse и надеемся поделиться им с читателями в этой статье.
Эта статья основана на версии Lightouse 5.2.0 и вводит процесс тестирования маяка, реализацию архитектурных модулей и расчеты индикатора производительности. Благодаря этой статье читатели могут узнать, как маяк делает автоматическое тестирование, как настроить некоторые элементы аудита в рамках маяка, а также насколько ключевые показатели эффективности моделируются и рассчитаны.
Эта статья будет состоять из следующих четырех разделов:
- Знакомство с Маяком
- Процесс тестирования маяка
- Реализация модуля Маяк
- Расчет показателей производительности Lighthouse
Знакомство с Маяком
Lighthouse — это инструмент автоматизации с открытым исходным кодом для улучшения качества веб-приложений. Просто дайте Lighthouse URL-адрес для проверки, и он проведет серию тестов для этой страницы, а затем создаст отчет о производительности страницы.
Как использовать Маяк
В настоящее время существует 4 официальных способа его использования:
Взяв в качестве примера инструменты разработчика Chrome, на панели «Аудит» пользователи могут настроить тестовую платформу, категорию теста, метод ограничения скорости и т. д., а также легко и быстро инициировать тест.
Отчет об испытаниях маяка
После теста по умолчанию будет сгенерирован отчет в формате HTML, как показано на следующем рисунке, который охватывает результаты теста по 5 основным категориям (категориям):
Каждая категория содержит ряд элементов аудита, и Lighthouse будет давать конкретные предложения по оптимизации и результаты диагностики по результатам элементов аудита, чтобы помочь разработчикам провести целевую оптимизацию.
В этом разделе кратко рассказывается об использовании Lighthouse и составе отчета о тестировании, а в следующем разделе будет представлен процесс тестирования Lighthouse.
Процесс тестирования маяка
Мы тестируем с помощью Node CLI и анализируем процесс тестирования Lighthouse.
Ссылаться наофициальная документация, после установки CLI введите следующую команду, чтобы выполнить тест
lighthouse --only-categories=performance https://google.com
Примечание. Приведенные выше команды тестируются только для категории производительности.
В CLI будет выводиться лог процесса тестирования.Скриншот показан ниже.В логе видно, что тест условно разбит на следующие этапы:
Через выходной журнал вы можете нарисовать тестовую блок-схему Lighthouse:
- Lighthouse устанавливает соединение с браузером.
- Первоначальная конфигурация теста и загрузка тестируемой страницы.
- Во время процесса загрузки страницы выполняется ряд коллекторов, каждый из которых собирает свою целевую информацию и генерирует промежуточные продукты (артефакты).
- Запустите серию проверок, каждая из которых получает необходимые данные от артефактов и вычисляет собственную оценку.
- На основе баллов по элементам аудита рассчитываются баллы по категориям, а отчеты агрегируются.
В этом разделе представлен процесс тестирования Lighthouse на основе журнала тестирования Lighthouse, а в следующем разделе будет представлена реализация модуля в этом процессе.
Реализация модуля Маяк
После предварительного понимания основного процесса тестирования, давайте взглянем на официальныйСхема архитектуры маяка:
На этой картинке показан основной процесс теста, из которого также можно обвести 4 основных модуля, и эти модули будут объяснены один за другим ниже.
Модуль драйвера
Двусторонняя связь и протокол DevTools
При запуске браузера Chrome вы можете--remote-debugging-port
Параметр задает порт удаленной отладки. Например, следующая команда может открыть Chrome и установить порт удаленной отладки на 9222.
chrome.exe --remote-debugging-port=9222
Тогда вы можете использовать адресhttp://localhost:9222Удаленная отладка, такая как следующая команда, чтобы сделать браузер Chrome для открытия новой вкладки.
curl http://localhost:9222/json/new
Команда также вернет информацию об этой вкладке, для которой необходимо указать webSocketDebuggerUrl, который является адресом подключения WebSocket для этой вкладки.
{
"id": "29989D...",
"url": "about:blank",
"webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/29989D...",
...
}
Модуль Driver содержит экземпляр Connection (отвечающий за связь с браузером), который инициализируется вызовом удаленного порта отладки./json/new
Команда открывает новую вкладку и использует возвращенный webSocketDebuggerUrl для установления соединения WebSocket с браузером, после чего возможна двусторонняя связь.
- Открыть новую вкладку
- Установить соединение WebSocket
После того, как обе стороны установят соединение WebSocket, они должны использовать протокол формата данных для связи.Этот протокол — протокол Chrome DevTools.Этот протокол использует JSON в качестве формата для определения имени метода и параметров команды.
Как показано на изображении ниже, отправка команды Page.navigate позволяет Chrome перейти на целевую страницу. Отправка команды Page.captureScreenshot позволяет Chrome генерировать данные снимка экрана для текущей страницы.
в соглашенииДокументацияВ , все управляющие инструкции и события разделены на несколько доменов (Domains), таких как Page, Network и т.д. Откройте поле Page, чтобы найти подробное описание примера директивы Page.navigate:
В дополнение к активно вызываемым командам, таким как навигация и захват экрана, когда мы вызываем команду включения поля, мы можем позже получать события уведомления, отправленные полем.
Lighthouse управляет браузером Chrome и воспринимает различные события во время загрузки страницы с помощью активных команд и уведомлений о событиях, определенных протоколом Chrome DevTools.
Ведение журнала
Двумя другими важными экземплярами в модуле Driver являются DevtoolsLog и NetworkRecorder, которые используются для структурированного хранения событий уведомлений, отправляемых браузером. Среди них DevtoolsLog будет записывать полный объем журналов в различных полях, а NetworkRecorder будет хранить только журналы, связанные с сетью, и анализировать текущий статус сетевых запросов (занят, простаивает) и т. д.
Сохраненная информация журнала будет использоваться в последующих проверках (Audits) модуля, о которых далее будет сказано ниже.
эмуляция
Последняя часть, о которой стоит упомянуть в модуле «Драйвер», — это эмуляция.Функция этого модуля заключается в имитации тестового оборудования, такого как имитация мобильного терминала/ПК-терминала, размера экрана, агента пользователя имитируемого устройства, файлов cookie. , ограничение скорости сети и т. д.
Настройки этих функций моделирования также достигаются путем отправки соответствующих команд манипулирования полями в браузер Chrome через модуль Connection.
Пока что мы разобрали основные компоненты модуля Driver, кратко подытожим: отвечающие за двустороннюю связь с браузером, запись журналов событий, настройки симулятора и т.д.
Модуль собирателя
Важной концепцией этого модуля является пропуск, и официальное определение прохода выглядит следующим образом:
controls how to load the requested URL and what information to gather about the page while loading.
То есть контролировать загрузку страницы и решать, какую информацию собирать в процессе загрузки страницы.
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.
То есть определить конфигурацию, такую как время ожидания загрузки страницы и необходимость записи файла трассировки. Каждый проход также определяет список сборщиков, сборщики могут считывать необходимую информацию со страницы и генерировать промежуточный продукт, Промежуточный продукт будет использоваться для последующего аудиторского анализа и, наконец, для создания отчета о тестировании.
Разобравшись с определением прохода, давайте рассмотрим конкретную конфигурацию прохода:
{
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',
... // 省略
],
},
... // 省略
}
Среди них нужно обратить внимание на сборщики.Каждый сборщик имеет соответствующий файл реализации с тем же именем в репозитории кода, и все они наследуются от одного и того же родительского класса Gatherer, который определяет три шаблонных метода, а подклассам нужны только Просто реализовать метод шаблона, который вам нужен.
class Gatherer {
// 在页面导航前
beforePass(passContext) { }
// 在页面loaded后
pass(passContext){ }
// 在页面加载完毕,且trace信息收集完毕后
afterPass(passContext, loadData) { }
}
В качестве примера возьмем относительно простой Gatherer, который реализует RuntimeExceptions.Этот экземпляр реализует два шаблонных метода жизненного цикла, beforePass и afterPass, из которых driver.on является прослушивателем событий, реализованным модулем Driver, описанным выше.
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);
}
// 在页面导航前,注册事件监听器,采集错误信息
beforePass(passContext) {
const driver = passContext.driver;
driver.on('Runtime.exceptionThrown', this._onRuntimeExceptionThrown);
}
// 在页面加载完毕后,解除事件监听
async afterPass(passContext) {
await passContext.driver.off('Runtime.exceptionThrown', this._onRuntimeExceptionThrown);
return this._exceptions;
}
}
С помощью этого эталонного примера мы также можем легко написать собственный сборщик, такой как сборщик для сбора заголовков страниц:
const Gatherer = require('./gatherer.js');
function getPageTitle() {
return document.title;
}
class PageTitle extends Gatherer {
afterPass(passContext) {
return passContext.driver.evaluateAsync(`(${getPageTitle.toString()}())`);
}
}
Мы только переопределяем метод afterPass, в середине жизни скрипт отправляется в браузер через модуль драйвера на выполнение, и получается результат выполнения.
Когда все сборщики, определенные в проходе, запускаются, генерируется промежуточный артефакт, после чего Lighthouse может отключиться от браузера и использовать только артефакты для последующего анализа.
Подводя итоги модуля Gatherer, этот модуль будет передавать эту конфигурацию, определять, как загружается страница, и запускать все сборщики, настроенные для сбора информации в процессе загрузки страницы и создания промежуточных артефактов. С артефактами вы можете перейти к следующему шагу модуля «Аудит».
Модуль аудита
Подобно сборщикам, аудиты, которые необходимо запустить, также определяются в файле конфигурации, и каждый аудит также имеет соответствующий файл реализации с тем же именем.
{
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',
// 省略
],
// 省略
}
Начнем с простейших ошибок-в-консоли, чтобы понять, как реализуется очередной аудит.
Статический метод определяется в каждом аудитеmeta()
, опишите аудит и объявите требуемые артефакты, а аудит ErrorLogs заявляет, что ему нужны промежуточные продукты, сгенерированные упомянутыми выше исключениями RuntimeException.
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()
, в этом методе может быть получен требуемый промежуточный продукт, а оценка и детали этого аудита могут быть рассчитаны на основе промежуточного продукта.
static audit(artifacts) {
// 获取所需的中间产物
const runtimeExceptions = artifacts.RuntimeExceptions;
// 数据的过滤与转换
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,
};
});
// 省略表格详情生成代码
...
// 计算出审计项的得分
const numErrors = tableRows.length;
return {
score: Number(numErrors === 0),
numericValue: numErrors,
details,
};
}
В приведенном выше примере мы можем реализовать настраиваемый элемент аудита, например заголовок страницы аудита:
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'
};
}
}
После запуска всех элементов аудита, определенных в файле конфигурации, вы получите оценку и подробные сведения о каждом элементе аудита, а затем войдете в модуль отчетов.
Модуль отчета
В файле конфигурации вы определяете элементы аудита, необходимые для каждой категории тестов, и долю веса каждого элемента аудита. Производительность показана ниже (производительность) элементов аудита, необходимых для этой категории тестов:
{
'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 будет рассчитываться на основе профиля и балла по каждой части элементов аудита, взвешенного рейтинга эффективности. И на основе оценок для каждого типа элементов аудита, разделенных по элементам аудита, а не по, для элементов аудита не приведены подробные детали тестирования и рекомендации по оптимизации.
Внедрение элементов аудита индекса производительности, таких как FCP
В процессе представления общего процесса тестирования, описанного выше, я выбрал для представления самый простой элемент аудита.В этом разделе я выберу индикаторы аудита производительности, которые вас больше интересуют, такие как FCP.
FCP (First Contentful Paint) Время отрисовки первого содержимого — это время от перехода по странице до момента, когда браузер отображает первое содержимое из DOM.
Моделирование ограничения скорости
Поскольку на производительность страницы сильно влияют такие параметры, как хост-сеть и частота ЦП, Lighthouse предлагает три способа имитации плохой хост-среды.При хорошем результате теста большинство пользователей получат более интуитивное представление о странице.
На панели «Аудит» Chrome Devtools вы можете увидеть три способа ограничения скорости:
Элементы конфигурации на рисунке выше соответствуют введению следующих трех методов ограничения скорости.
simulated
Throttling is simulated, resulting in faster audit runs with similar measurement accuracy
То есть моделируется ограничение скорости (ограничение скорости не выполняется при загрузке страницы. После загрузки страницы моделируется и рассчитывается значение индекса производительности при условии ограничения скорости), поэтому аудит может быть завершен в более высокая скорость с аналогичной точностью теста.
devtools
Typical DevTools throttling, with actual traffic shaping and CPU slowdown applied
То есть ограниченная по скорости через DevTools страница загружается под реальной ограниченной сетью и замедленным процессором.
no throttling
No network or CPU throttling used. (Useful when not evaluating performance)
То есть Lighthouse не выполняет дополнительных ограничений скорости, и это обычно используется, когда тестирование производительности не производится, или когда разработчики сами ограничивают скорость хоста.
Среди трех методов ограничения скорости Lighthouse действительно ограничивает только скорость сети, а CPU — это метод ограничения скорости devtools, который реализуется путем отправки инструкций в соответствующем поле в браузер Chrome через упомянутый выше модуль Driver:
// 开启CPU限速
function enableCPUThrottling(driver, throttlingSettings) {
const rate = throttlingSettings.cpuSlowdownMultiplier;
return driver.sendCommand('Emulation.setCPUThrottlingRate', {rate});
}
// 开启网络限速
function enableNetworkThrottling(driver, throttlingSettings) {
// 省略部分代码
return driver.sendCommand('Network.emulateNetworkConditions', conditions);
}
Информация о трассировке
При представлении прохода выше мы упомянули, что существует параметр, используемый для управления сбором трассировочной информации.Что такое трассировочная информация? Какая от этого польза?
На самом деле, большинство наших студентов знакомо с информацией о трассировке, и ее визуальное отображение находится на панели «Производительность» в инструментах разработки Chrome:
На этой панели визуализации вы можете увидеть ключевые узлы рендеринга FP, FCP, FMP и т. д. в процессе загрузки страницы, а также увидеть зависимости выполнения Parse HTML, Layout и JS, выполняемые основным потоком.
Когда сбор информации о трассировке настроен на проходе, Lighthouse может получить полную информацию о трассировке после загрузки страницы, из которой вы можете узнать ключевые узлы рендеринга, такие как FCP и FMP, при загрузке страницы.
Имитационный расчет FCP
При использовании devtools и отсутствии дросселирования для ограничения скорости, поскольку страница загружается в реальных условиях ограниченной сети, значение FCP, указанное в информации о трассировке, является значением FCP в условиях ограничения скорости, поэтому Lighthouse не требует дополнительной обработки.
Однако в режиме имитации ограничения скорости страница загружается без ограничения скорости, поэтому FCP в Trace является FCP, когда ограничение скорости не ограничено. оценки ниже. Далее мы сосредоточимся на расчете FCP в режиме моделирования.
Выше мы упоминали, что в модуле Driver есть NetworkRecorder. Этот модуль будет записывать детали всех сетевых запросов в процессе загрузки страницы. Lighthouse создаст соответствующий узел Network Node для каждого допустимого события сетевого запроса.
Информация трассировки также будет записывать события выполнения ЦП во время загрузки страницы, и Lighthouse создаст соответствующий узел узла ЦП для каждого допустимого события ЦП.
Затем Lighthouse найдет корневой узел (узел, запрашивающий документ) из узла сетевого запроса и установит зависимость между узлом ЦП и узлом сети в соответствии с алгоритмом зависимости узла и, наконец, сгенерирует ориентированный ациклический граф зависимостей загрузки страницы. .:
После создания полного графа зависимостей, необходимого для загрузки страницы, Lighthouse объединит время события FCP с информацией о трассировке для анализа графа зависимостей, необходимого для FCP страницы:
Получив граф зависимостей, требуемый страницей FCP, Lighthouse смоделировал и рассчитал время, необходимое для запроса ресурсов в графе зависимостей и выполнения событий ЦП в графе зависимостей в условиях ограничения скорости, чтобы получить время, необходимое для конкретный предел.оценки FCP в условиях скорости.
Имитация HTTP-запросов
Lighthouse рассчитывает время загрузки ресурса в определенных сетевых условиях, имитируя HTTP, а не инициируя сетевые запросы. Давайте посмотрим, как Lighthouse выполняет моделирование.
В приведенном выше коде мы видим, что Lighthouse вычисляет время, необходимое для ресурса в определенных условиях сети, имитируя HTTP. И это моделирование учитывает технологию мультиплексирования HTTP2, будь то запрос KeepAlive, трехстороннее рукопожатие TCP, окно перегрузки и другие детали.
Давайте используем картинку, чтобы подытожить и сравнить различия в процессе расчета FCP между двумя методами ограничения скорости:
Видно, что два метода ограничения скорости основаны на информации трассировки, предоставленной DevTools.В режиме ограничения скорости Simulate после получения значения FCP необходимо смоделировать и рассчитать оценочное значение в условиях ограничения скорости. В режиме Simulate speed limit аналогичным образом моделируются и рассчитываются другие показатели производительности, такие как FMP, SpeedIndex и т. д. До сих пор мы анализировали принцип реализации элемента аудита индикатора производительности Lighthouse FCP.
Суммировать
Эта статья кратко представляет Lighthouse, анализирует процесс тестирования и реализацию основного модуля Lighthouse и, наконец, представляет метод имитационного расчета ключевого показателя эффективности FCP, надеясь получить что-то для всех. В конце статьи будет выложена навигация по исходному коду упомянутых в статье модулей.Заинтересованные друзья могут глянуть.Добро пожаловать в общение.
Исходная навигация
Модуль драйвера
Модуль собирателя
Модуль аудита
Расчет FCP
- audit/fcp
- computed/fcp
- computed/lantern-fcp
- computed/lantern-metric
- computed/page-dependency-graph
- dependency-graph/base-node
- dependency-graph/tcp-connection
использованная литература
Эта статья была опубликована сКоманда внешнего интерфейса NetEase Cloud Music, Любое несанкционированное воспроизведение статьи запрещено. Мы всегда нанимаем, если вы готовы сменить работу и вам нравится облачная музыка, тоПрисоединяйтесь к нам!