Оптимизация стороннего JavaScript

Сторонние скрипты влияют на производительность , поэтому важно регулярно проверять их и использовать эффективные методы их загрузки . В этой кодовой лаборатории показано, как оптимизировать загрузку сторонних ресурсов. Он охватывает следующие методы:

  • Отложенная загрузка скрипта

  • Ленивая загрузка некритических ресурсов

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

Включенный пример приложения представляет собой простую веб-страницу с тремя функциями, полученными из сторонних источников:

  • Вставка видео

  • Библиотека визуализации данных для рендеринга линейного графика.

  • Виджет обмена информацией в социальных сетях

Скриншот страницы с выделенными сторонними ресурсами.
Сторонние ресурсы в примере приложения.

Вы начнете с измерения производительности приложения, а затем примените каждый метод для улучшения различных аспектов производительности приложения.

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

Сначала откройте пример приложения в полноэкранном режиме:

  1. Нажмите Remix to Edit , чтобы сделать проект доступным для редактирования.
  2. Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим полноэкранный .

Запустите аудит производительности Lighthouse на странице, чтобы установить базовую производительность:

  1. Нажмите «Control+Shift+J» (или «Command+Option+J» на Mac), чтобы открыть DevTools.
  2. Откройте вкладку «Маяк» .
  3. Нажмите «Мобильный» .
  4. Установите флажок Производительность . (Остальные флажки можно снять в разделе «Аудит».)
  5. Нажмите «Имитация быстрого 3G, замедление процессора в 4 раза » .
  6. Установите флажок Очистить хранилище .
  7. Нажмите «Выполнить аудит» .

Когда вы запускаете аудит на своем компьютере, точные результаты могут отличаться , но вы должны заметить, что время первой контентной отрисовки (FCP) довольно велико, и что Lighthouse предлагает две возможности для исследования: устранить ресурсы, блокирующие рендеринг , и выполнить предварительное подключение к необходимым происхождение . (Даже если все показатели в плюсе, оптимизация все равно приведет к улучшению.)

Снимок экрана аудита Lighthouse, показывающий 2,4-секундный FCP и две возможности: устранение ресурсов, блокирующих рендеринг, и предварительное подключение к необходимым источникам.

Отложить сторонний JavaScript

Аудит «Устранение ресурсов, блокирующих рендеринг» показал, что вы можете сэкономить некоторое время, отложив выполнение сценария, поступающего с d3js.org:

Снимок экрана: устранение аудита ресурсов, блокирующих рендеринг, с выделенным сценарием d3.v3.min.js.

D3.js — это библиотека JavaScript для создания визуализации данных. Файл script.js в примере приложения использует служебные функции D3 для создания линейной диаграммы SVG и добавления ее на страницу. Порядок операций здесь имеет значение: script.js должен запускаться после анализа документа и загрузки библиотеки D3, поэтому он включается прямо перед закрывающим тегом </body> в index.html .

Однако сценарий D3 включен в <head> страницы, что блокирует анализ остального документа:

Снимок экрана index.html с выделенным тегом сценария в заголовке.

Два магических атрибута могут разблокировать парсер при добавлении в тег скрипта:

  • async гарантирует, что сценарии загружаются в фоновом режиме и выполняются при первой же возможности после завершения загрузки.

  • defer гарантирует, что скрипты загружаются в фоновом режиме и выполняются после полного завершения синтаксического анализа .

Поскольку эта диаграмма не имеет особого значения для всей страницы и, скорее всего, будет находиться в нижней части страницы, используйте defer , чтобы убедиться, что синтаксический анализатор не блокируется.

Шаг 1. Загрузите сценарий асинхронно с атрибутом defer .

В строке 17 в index.html добавьте атрибут defer к элементу <script> :

<script src="https://d3js.org/d3.v3.min.js" defer></script>

Шаг 2. Обеспечьте правильный порядок операций.

Теперь, когда D3 отложен, script.js будет запущен до того, как D3 будет готов, что приведет к ошибке.

Скрипты с атрибутом defer выполняются в том порядке, в котором они были указаны. Чтобы гарантировать выполнение script.js после того, как D3 будет готов, добавьте к нему defer и переместите его в <head> документа, сразу после элемента <script> D3. Теперь он больше не блокирует парсер и загрузка начинается раньше.

<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>

Ленивая загрузка сторонних ресурсов

Все ресурсы, находящиеся в нижней части страницы, являются хорошими кандидатами на отложенную загрузку .

В примере приложения есть видео YouTube, встроенное в iframe . Чтобы узнать, сколько запросов делает страница и какие приходят из встроенного iframe YouTube:

  1. Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим полноэкранный .
  2. Нажмите «Control+Shift+J» (или «Command+Option+J» на Mac), чтобы открыть DevTools.
  3. Откройте вкладку Сеть .
  4. Установите флажок Отключить кеш .
  5. В раскрывающемся меню «Регулирование» выберите «Быстрый 3G» .
  6. Перезагрузите страницу.

Снимок экрана панели DevTools Network.

На панели «Сеть» видно, что страница выполнила в общей сложности 28 запросов и передала почти 1 МБ сжатых ресурсов.

Чтобы определить запросы, сделанные iframe YouTube, найдите идентификатор видео 6lfaiXM6waw в столбце «Инициатор» . Чтобы сгруппировать все запросы по домену:

  • На панели «Сеть» щелкните правой кнопкой мыши заголовок столбца.

  • В раскрывающемся меню выберите столбец Домены .

  • Чтобы отсортировать запросы по домену, щелкните заголовок столбца Домены .

Новая сортировка показывает, что есть дополнительные запросы к доменам Google. Всего iframe YouTube выполняет 14 запросов на скрипты, таблицы стилей, изображения и шрифты. Но если пользователи на самом деле не прокручивают страницу вниз, чтобы воспроизвести видео, им на самом деле не нужны все эти ресурсы.

Ожидая ленивой загрузки видео до тех пор, пока пользователь не прокрутит страницу до этого раздела, вы сокращаете количество запросов, которые изначально делает страница. Такой подход экономит данные пользователей и ускоряет первоначальную загрузку.

Один из способов реализации отложенной загрузки — использование Intersection Observer , API браузера, который уведомляет вас, когда элемент входит или выходит из области просмотра браузера.

Шаг 1. Запретите первоначальную загрузку видео

Чтобы выполнить отложенную загрузку iframe видео, необходимо сначала запретить его загрузку обычным способом. Сделайте это, заменив атрибут src атрибутом data-src , чтобы указать URL-адрес видео:

<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

data-src — это атрибут данных , который позволяет хранить дополнительную информацию о стандартных элементах HTML. Атрибут данных может иметь любое имя, главное, чтобы оно начиналось с «data-».

Iframe без src просто не загрузится.

Шаг 2. Используйте Intersection Observer для отложенной загрузки видео.

Чтобы загрузить видео, когда пользователь прокручивает его, вам нужно знать, когда это происходит. Именно здесь в дело вступает API Intersection Observer. API Intersection Observer позволяет зарегистрировать функцию обратного вызова, которая выполняется всякий раз, когда элемент, который вы хотите отслеживать, входит или выходит из области просмотра.

Для начала создайте новый файл и назовите его lazy-load.js :

  • Нажмите «Новый файл» и дайте ему имя.
  • Нажмите «Добавить этот файл» .

Добавьте тег сценария в заголовок документа:

 <script src="/lazy-load.js" defer></script>

В lazy-load.js создайте новый IntersectionObserver и передайте ему функцию обратного вызова для запуска:

// create a new Intersection Observer
let observer = new IntersectionObserver(callback);

Теперь дайте observer целевой элемент для просмотра (в данном случае iframe видео), передав его в качестве аргумента в методе observe :

// the element that you want to watch
const element = document.querySelector('iframe');

// register the element with the observe method
observer.observe(element);

callback получает список объектов IntersectionObserverEntry и сам объект IntersectionObserver . Каждая запись содержит target элемент и свойства, описывающие его размеры, положение, время входа в область просмотра и многое другое. Одним из свойств IntersectionObserverEntry является isIntersecting — логическое значение, которое равно true когда элемент попадает в область просмотра.

В этом примере target является iframe . isIntersecting принимает значение true , когда target входит в область просмотра. Чтобы увидеть это в действии, замените callback следующей функцией:

let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(entry => {
      console.log(entry.target);
      console.log(entry.isIntersecting);
    });
  });
  1. Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим полноэкранный .
  2. Нажмите «Control+Shift+J» (или «Command+Option+J» на Mac), чтобы открыть DevTools.
  3. Откройте вкладку Консоль .

Попробуйте прокрутить вверх и вниз. Вы должны увидеть значение изменения isIntersecting и целевой элемент, зарегистрированный на консоли.

Чтобы загрузить видео, когда пользователь прокручивает его до его позиции, используйте isIntersecting в качестве условия для запуска функции loadElement , которая получает значение из data-src элемента iframe и устанавливает его в качестве атрибута src элемента iframe . Эта замена запускает загрузку видео. Затем, как только видео загрузится, вызовите метод unobserve observer , чтобы прекратить просмотр целевого элемента:

let observer = new IntersectionObserver(function (entries, observer) {
  entries.forEach(entry => {
    console.log(entry.target);
    console.log(entry.isIntersecting);
  });
});
    if (entry.isIntersecting) {
      // do this when the element enters the viewport
      loadElement(entry.target);
      // stop watching
      observer.unobserve(entry.target);
    }
  });
});

function loadElement(element) {
  const src = element.getAttribute('data-src');
  element.src = src;
}

Шаг 3. Переоцените производительность

Чтобы увидеть, как изменился размер и количество ресурсов, откройте панель DevTools Network и снова перезагрузите страницу. На панели «Сеть» видно, что страница выполнила 14 запросов и весила всего 260 КБ. Это значительное улучшение!

Теперь прокрутите страницу вниз и обратите внимание на панель «Сеть» . Когда вы перейдете к видео, вы должны увидеть, что страница вызывает дополнительные запросы.

Предварительное подключение к необходимым источникам

Вы отложили некритичный JavaScript и отложенно загрузили запросы YouTube, поэтому теперь пришло время оптимизировать оставшийся сторонний контент.

Добавление атрибута rel=preconnect к ссылке указывает браузеру установить соединение с доменом до того, как будет выполнен запрос этого ресурса. Этот атрибут лучше всего использовать для источников, которые предоставляют ресурсы, которые, как вы уверены, необходимы странице.

Аудит Lighthouse, который вы выполнили на первом этапе, предложенном в разделе «Предварительное подключение к необходимым источникам» , позволяет сэкономить около 400 мс, установив ранние подключения к staticxx.facebook.com и youtube.com:

Предварительное подключение к необходимому аудиту источников с выделенным доменом staticxx.facebook.com.

Поскольку видео на YouTube теперь загружается отложенно, остается только staticxx.facebook.com, источник виджета для обмена в социальных сетях. Установить раннее соединение с этим доменом так же просто, как добавить тег <link> в <head> документа:

  <link rel="preconnect" href="https://staticxx.facebook.com">

Переоцените производительность

Вот состояние страницы после оптимизации . Следуйте инструкциям из раздела «Измерение производительности» лаборатории кода, чтобы запустить еще один аудит Lighthouse.

Аудит маяка показывает 1 секунду FCP и оценку производительности 99.