Gatherers и артефакты

Система сбора данных в Lighthouse построена вокруг концепции gatherers (сборщиков), которые извлекают информацию из браузера во время выполнения аудита. Каждый gatherer отвечает за получение строго определённого типа данных, формируя на выходе артефакты — структурированные результаты, используемые аудитами.

В основе лежит разделение ответственности:

  • Gatherers — извлекают данные
  • Artifacts — представляют данные
  • Audits — анализируют артефакты

Такое разделение обеспечивает масштабируемость и повторное использование логики.


Жизненный цикл Gatherer

Каждый gatherer проходит три ключевых этапа:

1. beforePass

Вызывается перед загрузкой страницы. Используется для настройки окружения:

  • включение логирования
  • установка слушателей событий
  • конфигурация браузера через Chrome DevTools Protocol (CDP)
async beforePass({driver}) {
  await driver.sendCommand('Network.enable');
}

2. pass

Выполняется во время загрузки страницы:

  • сбор данных в процессе рендеринга
  • перехват сетевых запросов
  • мониторинг DOM
async pass({driver}) {
  this.requests = [];
  driver.on('Network.requestWillBeSent', req => {
    this.requests.push(req);
  });
}

3. afterPass

Запускается после полной загрузки страницы:

  • финальный сбор данных
  • обработка накопленной информации
  • формирование артефакта
async afterPass() {
  return this.requests;
}

Контекст выполнения

Gatherers работают в двух средах:

Node.js (основной процесс)

  • выполнение логики gatherer
  • взаимодействие с CDP через driver
  • доступ к файловой системе

Браузер (через evaluate)

  • выполнение кода внутри страницы
  • доступ к DOM и window
const result = await driver.evaluateAsync(`
  new Promise(resolve => {
    resolve(document.title);
  });
`);

Driver и Chrome DevTools Protocol

Ключевой компонент — driver, абстракция над CDP. Позволяет:

  • отправлять команды браузеру
  • подписываться на события
  • выполнять JS в контексте страницы
await driver.sendCommand('Page.enable');

Примеры возможностей:

  • Network.* — отслеживание запросов
  • Performance.* — метрики производительности
  • DOM.* — работа с DOM

Артефакты: структура и назначение

Артефакт — это результат работы gatherer, представленный в виде JSON-совместимой структуры.

Пример:

{
  "URL": "https://example.com",
  "Timing": {
    "firstContentfulPaint": 1234
  }
}

Основные характеристики:

  • детерминированность
  • сериализуемость
  • независимость от среды выполнения

Артефакты сохраняются и передаются аудитам без изменений.


Типы артефактов

Простые

  • строки
  • числа
  • массивы

Сложные

  • объекты с вложенной структурой
  • коллекции событий
  • результаты трассировки

Пример сложного артефакта:

{
  resources: [
    {url: 'style.css', type: 'stylesheet'},
    {url: 'app.js', type: 'script'}
  ],
  totalSize: 34567
}

Связь Gatherer и Artifact

Каждый gatherer объявляет имя артефакта, который он возвращает.

class MyGatherer {
  get name() {
    return 'MyArtifact';
  }
}

Это имя используется:

  • для регистрации
  • для доступа в аудитах

Использование артефактов в аудитах

Аудиты получают доступ к артефактам через объект artifacts:

static audit(artifacts) {
  const data = artifacts.MyArtifact;
  return {
    score: data.length > 0 ? 1 : 0
  };
}

Артефакты не модифицируются аудитами — только читаются.


Асинхронность и производительность

Gatherers активно используют async/await:

  • параллельный сбор данных
  • ожидание событий
  • синхронизация с браузером

Важно:

  • избегать блокирующих операций
  • минимизировать количество evaluate
  • переиспользовать данные

Кэширование и повторное использование

Lighthouse автоматически кэширует артефакты:

  • один gatherer → один запуск
  • несколько аудитов используют один артефакт

Это снижает:

  • время выполнения
  • нагрузку на браузер

Пример кастомного Gatherer

const Gatherer = require('lighthouse').Gatherer;

class MetaDescriptionGatherer extends Gatherer {
  async afterPass({driver}) {
    const description = await driver.evaluateAsync(`
      new Promise(resolve => {
        const el = document.querySelector('meta[name="description"]');
        resolve(el ? el.content : null);
      });
    `);

    return description;
  }
}

module.exports = MetaDescriptionGatherer;

Регистрация Gatherer

В конфигурации Lighthouse:

module.exports = {
  passes: [
    {
      passName: 'defaultPass',
      gatherers: [
        './gatherers/meta-description.js'
      ]
    }
  ]
};

Ошибки и обработка исключений

Gatherers должны быть устойчивыми к сбоям:

  • сетевые ошибки
  • отсутствие элементов
  • таймауты

Рекомендуется:

  • использовать try/catch
  • возвращать null вместо выброса ошибок
try {
  return await driver.evaluateAsync(...);
} catch (e) {
  return null;
}

Ограничения и best practices

Не рекомендуется:

  • выполнять тяжёлые вычисления внутри gatherer
  • дублировать логику аудитов
  • использовать глобальное состояние

Рекомендуется:

  • минимизировать объем собираемых данных
  • возвращать только необходимое
  • разделять gatherers по ответственности

Взаимодействие с Passes

Gatherers группируются в passes — этапы выполнения аудита.

Каждый pass:

  • управляет жизненным циклом страницы
  • определяет порядок gatherers
  • может иметь собственные настройки (например, throttling)

Расширение системы

Добавление нового gatherer:

  1. Создание класса
  2. Реализация lifecycle-методов
  3. Регистрация в конфигурации
  4. Использование в аудитах

Диагностика и отладка

Инструменты:

  • логирование через lighthouse-logger
  • Chrome DevTools
  • сохранение артефактов
const log = require('lighthouse-logger');
log.info('Category', 'Message');

Взаимодействие с трассировкой (Trace)

Некоторые gatherers используют trace:

  • анализ производительности
  • измерение времени рендеринга

Trace собирается отдельно и передаётся как артефакт:

artifacts.traces.defaultPass

Взаимодействие с DevTools Log

DevTools Log (devtoolsLog) — ещё один важный артефакт:

  • содержит сетевые события
  • используется для анализа загрузки
artifacts.devtoolsLogs.defaultPass

Детерминизм и воспроизводимость

Ключевое требование:

  • одинаковый вход → одинаковый артефакт

Для этого:

  • отключаются кэши
  • фиксируются условия сети
  • используется throttling

Роль Gatherers в архитектуре Lighthouse

Gatherers формируют фундамент всей системы:

  • изолируют доступ к данным
  • стандартизируют формат результатов
  • обеспечивают независимость аудитов

Именно через них Lighthouse превращает поведение браузера в структурированную, анализируемую информацию.