Как выявить ресурсоемкий код JavaScript

Тяжелый код JavaScript может отрицательно повлиять как на скорость загрузки страницы, так и на ее интерактивность. Современные веб-приложения больше, чем когда-либо, зависят от JavaScript из нескольких источников. К ним относятся код самого приложения (и код фреймворка, на котором оно основано), а также сторонние скрипты, добавляющие такие функции, как виджеты чата и видеопроигрыватели. Зачастую разработчики забывают о скриптах, которые используются для сбора статистики и маркетинга.

Определить основные причины, по которым веб-страница не отвечает, может быть непросто. Для этого требуются определенные знания, чтобы выполнить трассировку или профилирование производительности веб-страницы и интерпретировать результаты. Кроме того, данные наблюдений часто сильно отличаются от лабораторных данных, которые воспроизводят лишь небольшое подмножество реальных пользовательских сценариев. Это может затруднить выявление основных причин низкой производительности, особенно при взаимодействии.

Long Animation Frames API – это легковесный API, который можно использовать для выявления тяжелых скриптов JavaScript в полевых условиях. Это может быть как один скрипт, который выполняется долго, так и скрипт, который выполняется несколько раз за жизненный цикл страницы.

Рекомендации по внедрению

Длительные кадры анимации отслеживаются с помощью интерфейса PerformanceObserver. Если на отрисовку кадра анимации уходит больше 50 мс, создается запись long-animation-frame. Запись содержит информацию о длительном кадре анимации, включая его продолжительность и скрипты, которые выполнялись во время его отрисовки.

Запись long-animation-frame содержит свойство scripts, которое представляет собой массив объектов PerformanceScript. Каждый объект PerformanceScript содержит информацию о скрипте, который выполнялся во время длительного кадра анимации, включая sourceURL и duration скрипта.

Пример определения самых длинных скриптов, которые приводят к длительным кадрам анимации

// Accumulate all script entries across the page lifecycle so no
// data is lost between observer callbacks.
const allScripts = [];

const observer = new PerformanceObserver(list => {
  // Collect all script entries across frames to find the biggest offenders.
  allScripts.push(...list.getEntries().flatMap(entry => entry.scripts));

  // Group by sourceURL so you can identify which scripts contribute
  // the most total time, even if each individual invocation is short.
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource = scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));

  // Only include scripts above a certain threshold to reduce noise.
  const heavyScripts = processedScripts.filter(script => {
    return script.totalDuration > 100;
  });

  // Sort by total duration so the worst offenders appear first,
  // making it easier to prioritize optimization efforts.
  heavyScripts.sort((a, b) => b.totalDuration - a.totalDuration);

  // Log to the console for local debugging. In production, replace
  // this with a call to send the data to your analytics service.
  console.table(heavyScripts);
});

// Use buffered: true to capture any long frames that occurred before
// this observer was registered.
observer.observe({type: 'long-animation-frame', buffered: true});

Рекомендации

  • РЕКОМЕНДУЕТСЯ использовать Long Animation Frames API вместо альтернативных вариантов, таких как JS Self-Profiling API, который требует больше ресурсов во время выполнения.
  • РЕКОМЕНДУЕТСЯ обобщать ключевую информацию, поскольку Long Animation Frames API содержит много подробностей.
  • РЕКОМЕНДУЕТСЯ отправлять необходимую информацию в сервис аналитики в рабочей среде.

Поддержка браузеров и резервные стратегии

Браузеры, которые не поддерживают Long Animation Frames API, игнорируют его, поэтому его можно использовать без резервных вариантов. В большинстве случаев возможности повышения производительности, которые он выявляет, будут применимы и к другим браузерам.