Не боритесь со сканером предварительной загрузки браузера

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

Один из часто упускаемых из виду аспектов оптимизации скорости загрузки страниц — это знание внутренних механизмов браузера. Браузеры выполняют определенные оптимизации для повышения производительности способами, недоступными для разработчиков, — но только до тех пор, пока эти оптимизации не будут непреднамеренно сорваны.

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

Что такое сканер предварительной загрузки?

В каждом браузере есть основной HTML-парсер, который токенизирует необработанную разметку и преобразует её в объектную модель . Этот процесс продолжается до тех пор, пока парсер не остановится, обнаружив блокирующий ресурс , например, таблицу стилей, загруженную с помощью элемента <link> , или скрипт, загруженный с помощью элемента <script> без атрибутов async или defer .

Диаграмма парсера HTML.
Рис. 1: Схема, показывающая, как может быть заблокирован основной HTML-парсер браузера. В данном случае парсер сталкивается с элементом <link> для внешнего CSS-файла, что блокирует браузеру возможность анализа остальной части документа — или даже его отображения — до тех пор, пока CSS-файл не будет загружен и проанализирован.

В случае с CSS-файлами рендеринг блокируется, чтобы предотвратить «мигание» нестилизованного контента (FOUC) , то есть кратковременное отображение нестилизованной версии страницы перед применением к ней стилей.

Домашняя страница web.dev в нестилизованном состоянии (слева) и в стилизованном состоянии (справа).
Рис. 2: Имитационный пример FOUC. Слева — главная страница web.dev без стилей. Справа — та же страница с примененными стилями. Состояние без стилей может возникнуть мгновенно, если браузер не блокирует отрисовку во время загрузки и обработки таблицы стилей.

Браузер также блокирует разбор и отрисовку страницы, когда встречает элементы <script> без атрибутов defer или async .

Причина в том, что браузер не может точно знать, будет ли тот или иной скрипт изменять DOM, пока основной HTML-парсер продолжает свою работу. Именно поэтому стало распространенной практикой загружать JavaScript в конце документа, чтобы минимизировать влияние блокировки парсинга и рендеринга.

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

Схема, демонстрирующая как основной HTML-парсер (слева), так и сканер предварительной загрузки (справа), который является вторичным HTML-парсером.
Рис. 3: Диаграмма, иллюстрирующая параллельную работу сканера предварительной загрузки с основным HTML-парсером для спекулятивной загрузки ресурсов. Здесь основной HTML-парсер блокируется, поскольку он загружает и обрабатывает CSS, прежде чем сможет начать обработку разметки изображения в элементе <body> , но сканер предварительной загрузки может просмотреть исходную разметку, чтобы найти этот ресурс изображения и начать его загрузку до того, как основной HTML-парсер разблокируется.

Роль сканера предварительной загрузки носит спекулятивный характер , то есть он анализирует необработанную разметку, чтобы найти ресурсы для оперативной загрузки до того, как их обнаружит основной HTML-парсер.

Как определить, что сканер предварительной загрузки работает

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

В качестве примера возьмем эту страницу с простым текстом и изображениями, содержащую таблицу стилей. Поскольку файлы CSS блокируют как рендеринг, так и анализ, вы вводите искусственную задержку в две секунды для таблицы стилей через прокси-сервис. Эта задержка позволяет легче увидеть в диаграмме потоковой загрузки, где работает сканер предварительной загрузки.

Диаграмма водопада сети WebPageTest иллюстрирует искусственную задержку в 2 секунды, наложенную на таблицу стилей.
Рис. 4: Диаграмма сетевого трафика WebPageTest для веб-страницы , запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Несмотря на то, что загрузка таблицы стилей искусственно задерживается на две секунды через прокси-сервер, изображение, расположенное позже в полезной нагрузке разметки, обнаруживается сканером предварительной загрузки.

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

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

Внедренные async скрипты

Допустим, у вас в разделе <head> есть HTML-код, содержащий встроенный JavaScript, например, такой:

<script>
  const scriptEl = document.createElement('script');
  scriptEl.src = '/yall.min.js';

  document.head.appendChild(scriptEl);
</script>

Внедряемые скрипты по умолчанию являются async , поэтому при внедрении этого скрипта он будет вести себя так, как если бы к нему был применен атрибут async . Это означает, что он будет выполняться как можно быстрее и не блокировать рендеринг. Звучит оптимально, не правда ли? Однако, если предположить, что этот встроенный <script> находится после элемента <link> , который загружает внешний CSS-файл, вы получите неоптимальный результат:

На этом графике WebPageTest показано, как отключается сканирование предварительной загрузки при внедрении скрипта.
Рис. 5: Диаграмма сетевого трафика WebPageTest для веб-страницы , запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Страница содержит одну таблицу стилей и внедренный async скрипт. Сканер предварительной загрузки не может обнаружить скрипт на этапе блокировки рендеринга, поскольку он внедряется на стороне клиента.

Давайте разберем, что здесь произошло:

  1. Через 0 секунд запрашивается основной документ.
  2. Через 1,4 секунды приходит первый байт запроса на навигацию.
  3. Через 2,0 секунды запрашиваются CSS-код и изображение.
  4. Поскольку парсер блокирует загрузку таблицы стилей, а встроенный JavaScript, внедряющий async скрипт, выполняется после этой таблицы стилей, через 2,6 секунды, функциональность, предоставляемая этим скриптом, становится доступна не так быстро, как могла бы.

Это неоптимальный вариант, поскольку запрос на скрипт поступает только после завершения загрузки таблицы стилей. Это задерживает запуск скрипта на максимально возможное время. Напротив, поскольку элемент <img> обнаруживается в предоставленной сервером разметке, он обнаруживается сканером предварительной загрузки.

Итак, что произойдет, если использовать обычный тег <script> с атрибутом async вместо внедрения скрипта в DOM?

<script src="/yall.min.js" async></script>

Вот результат:

Диаграмма WebPageTest, отображающая структуру сети, показывает, что асинхронный скрипт, загруженный с помощью элемента <script> в HTML, по-прежнему обнаруживается сканером предварительной загрузки браузера, даже несмотря на то, что основной HTML-парсер браузера блокируется во время загрузки и обработки таблицы стилей.
Рис. 6: Диаграмма сетевого трафика WebPageTest для веб-страницы , запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Страница содержит одну таблицу стилей и один async элемент <script> . Сканер предварительной загрузки обнаруживает скрипт на этапе блокировки рендеринга и загружает его одновременно с CSS.

Может возникнуть соблазн предположить, что эти проблемы можно решить с помощью rel=preload . Это, безусловно, сработает, но может повлечь за собой некоторые побочные эффекты. В конце концов, зачем использовать rel=preload для решения проблемы, которой можно избежать, не внедряя элемент <script> в DOM?

Диаграмма WebPageTest, демонстрирующая, как подсказка ресурса rel=preload используется для содействия обнаружению асинхронно внедренного скрипта — хотя и таким образом, который может иметь непредвиденные побочные эффекты.
Рис. 7: Диаграмма сетевого трафика WebPageTest, отображающая веб-страницу , запущенную в Chrome на мобильном устройстве через имитированное 3G-соединение. Страница содержит одну таблицу стилей и внедренный async скрипт, но async скрипт предварительно загружен, чтобы гарантировать его более быстрое обнаружение.

Предварительная загрузка "решает" проблему, но создает новую: async скрипт в первых двух демонстрациях — несмотря на то, что он загружен в <head> — загружается с "низким" приоритетом, в то время как таблица стилей загружается с "высоким" приоритетом. В последней демонстрации, где async скрипт предварительно загружен, таблица стилей по-прежнему загружается с "высоким" приоритетом, но приоритет скрипта повышается до "высокого".

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

Ответ здесь прост: если скрипт необходим при запуске, не стоит обходить сканер предварительной загрузки, внедряя его в DOM. Поэкспериментируйте по мере необходимости с размещением элемента <script> , а также с такими атрибутами, как defer и async .

Ленивая загрузка с помощью JavaScript

Ленивая загрузка — отличный метод экономии данных, который часто применяется к изображениям. Однако иногда ленивая загрузка ошибочно применяется к изображениям, которые, так сказать, находятся «выше линии сгиба».

Это создает потенциальные проблемы с обнаружением ресурсов в отношении сканера предварительной загрузки и может неоправданно задерживать время, необходимое для обнаружения ссылки на изображение, его загрузки, декодирования и отображения. Рассмотрим, например, следующую разметку изображения:

<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

Использование префикса data- — распространённый шаблон в отложенных загрузчиках, работающих на основе JavaScript. Когда изображение прокручивается в область просмотра, отложенный загрузчик удаляет префикс data- , то есть в приведённом выше примере ` data-src становится src . Это обновление побуждает браузер загрузить ресурс.

Этот шаблон не представляет проблемы, пока не применяется к изображениям, находящимся в области просмотра во время запуска. Поскольку сканер предварительной загрузки считывает атрибут data-src не так, как атрибут src (или srcset ), ссылка на изображение не обнаруживается раньше. Хуже того, загрузка изображения задерживается до тех пор , пока JavaScript-код, использующий ленивую загрузку, не будет загружен, скомпилирован и выполнен.

Диаграмма сетевого трафика WebPageTest показывает, как изображение, загружаемое отложенным способом и находящееся в области просмотра во время запуска, неизбежно задерживается, потому что сканер предварительной загрузки браузера не может найти ресурс изображения, и загружается только тогда, когда загружается JavaScript, необходимый для работы отложенной загрузки. Изображение обнаруживается гораздо позже, чем должно быть.
Рис. 8: Диаграмма сетевого трафика WebPageTest, отображающая веб-страницу , запущенную в Chrome на мобильном устройстве через имитированное 3G-соединение. Ресурс изображения загружается с задержкой, хотя он виден в области просмотра при запуске. Это сводит на нет работу сканера предварительной загрузки и вызывает ненужную задержку.

В зависимости от размера изображения, который может зависеть от размера области просмотра, оно может быть потенциальным элементом для Largest Contentful Paint (LCP) . Когда сканер предварительной загрузки не может предварительно загрузить ресурс изображения — возможно, в тот момент, когда таблицы стилей страницы блокируют отрисовку, — LCP страдает.

Решение заключается в изменении разметки изображения:

<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

Это оптимальный вариант для изображений, находящихся в области просмотра во время запуска, поскольку сканер предварительной загрузки обнаружит и загрузит ресурс изображения быстрее.

Диаграмма сетевого трафика WebPageTest, отображающая сценарий загрузки изображения в области просмотра при запуске. Изображение не загружается отложенно, то есть его загрузка не зависит от скрипта, благодаря чему сканер предварительной загрузки может обнаружить его раньше.
Рис. 9: Диаграмма водопада сети WebPageTest для веб-страницы , запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Сканер предварительной загрузки обнаруживает ресурс изображения до начала загрузки CSS и JavaScript, что дает браузеру преимущество в его загрузке.

В этом упрощенном примере результат — улучшение LCP на 100 миллисекунд при медленном соединении. Это может показаться не таким уж большим улучшением, но оно становится таковым, если учесть, что решение представляет собой быструю корректировку разметки, и что большинство веб-страниц сложнее, чем приведенные примеры. Это означает, что кандидатам на LCP, возможно, придется конкурировать за пропускную способность со многими другими ресурсами, поэтому подобные оптимизации становятся все более важными.

фоновые изображения CSS

Помните, что сканер предварительной загрузки браузера сканирует разметку . Он не сканирует другие типы ресурсов, такие как CSS, которые могут включать в себя получение изображений, на которые ссылается свойство background-image .

Подобно HTML, браузеры обрабатывают CSS и преобразуют его в собственную объектную модель, известную как CSSOM . Если в процессе построения CSSOM обнаруживаются внешние ресурсы, эти ресурсы запрашиваются в момент обнаружения, а не сканером предварительной загрузки.

Допустим, в качестве LCP-кандидата для вашей страницы используется элемент со свойством CSS ` background-image . Вот что происходит при загрузке ресурсов:

Диаграмма водопада сети WebPageTest, отображающая страницу с кандидатом на LCP-загрузку из CSS с использованием свойства background-image. Поскольку изображение-кандидат на LCP-загрузку находится в ресурсе, который сканер предварительной загрузки браузера не может проверить, загрузка ресурса задерживается до тех пор, пока не будет загружен и обработан CSS, что задерживает время отрисовки кандидата на LCP-загрузку.
Рис. 10: Диаграмма сетевого трафика WebPageTest для веб-страницы , запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Кандидатом на роль LCP на странице является элемент со свойством CSS background-image (строка 3). Запрашиваемое изображение начинает загружаться только после того, как его обнаружит CSS-парсер.

В этом случае сканер предварительной загрузки не столько отключается, сколько не участвует. Тем не менее, если LCP-кандидат на странице получен из свойства CSS background-image , вам потребуется предварительно загрузить это изображение:

<!-- Make sure this is in the <head> below any
     stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">

Подсказка rel=preload незначительна, но она помогает браузеру обнаружить изображение раньше, чем это произошло бы в противном случае:

Диаграмма сетевого трафика WebPageTest показывает, что фоновое изображение CSS (кандидат на роль LCP) загружается значительно быстрее благодаря использованию подсказки rel=preload. Время загрузки LCP сокращается примерно на 250 миллисекунд.
Рис. 11: Диаграмма водопада сети WebPageTest для веб-страницы , запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Кандидатом на роль LCP на странице является элемент со свойством CSS background-image (строка 3). Подсказка rel=preload помогает браузеру обнаружить изображение примерно на 250 миллисекунд раньше, чем без этой подсказки.

С помощью подсказки rel=preload кандидат на LCP обнаруживается быстрее, что сокращает время LCP-загрузки. Хотя эта подсказка помогает решить эту проблему, лучшим вариантом может быть оценка того, нужно ли загружать ваш кандидат на LCP-загрузку изображения из CSS. С помощью тега <img> у вас будет больше контроля над загрузкой изображения, подходящего для области просмотра, и вы сможете позволить сканеру предварительной загрузки обнаружить его.

Слишком большое количество ресурсов направлено в сеть.

Встраивание (инлайнинг) — это практика размещения ресурса внутри HTML-кода. Вы можете встраивать таблицы стилей в элементы <style> , скрипты в элементы <script> и практически любой другой ресурс, используя кодировку base64 .

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

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

Рассмотрим эту страницу в качестве примера. При определенных условиях кандидатом на включение в LCP является изображение в верхней части страницы, а CSS находится в отдельном файле, загружаемом элементом <link> . На странице также используются четыре веб-шрифта, которые запрашиваются как отдельные файлы из ресурса CSS.

Диаграмма водопада сети WebPageTest для страницы с внешним CSS-файлом, содержащим ссылки на четыре шрифта. Изображение-кандидат LCP обнаруживается сканером предварительной загрузки в установленный срок.
Рис. 12: Диаграмма сетевого трафика WebPageTest для веб-страницы , запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Кандидатом на роль LCP на странице является изображение, загруженное из элемента <img> , но оно обнаруживается сканером предварительной загрузки, поскольку CSS и шрифты, необходимые для страницы, загружаются в отдельных ресурсах, что не задерживает работу сканера предварительной загрузки.

А что произойдет, если CSS и все шрифты будут встроены как ресурсы base64?

Диаграмма сетевого трафика WebPageTest для страницы с внешним CSS-файлом, содержащим ссылки на четыре шрифта. Сканер предварительной загрузки значительно задерживает обнаружение изображения LCP.
Рис. 13: Диаграмма водопада сети WebPageTest для веб-страницы , запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Кандидатом на роль LCP на странице является изображение, загруженное из элемента <img> , но встраивание CSS и его четырех ресурсов шрифтов в ` `Задерживает обнаружение образа сканером предварительной загрузки до тех пор, пока эти ресурсы не будут полностью загружены.

В данном примере встраивание кода приводит к негативным последствиям для LCP, а также для производительности в целом. Версия страницы, в которой ничего не встраивается, отображает изображение LCP примерно за 3,5 секунды. Страница, в которой всё встраивается, отображает изображение LCP чуть более чем за 7 секунд.

Здесь в дело вступает не только сканер предварительной загрузки. Встраивание шрифтов — не лучшая стратегия, поскольку base64 — неэффективный формат для бинарных ресурсов. Ещё один фактор заключается в том, что внешние ресурсы шрифтов не загружаются, если CSSOM не сочтёт их необходимыми. Когда эти шрифты встраиваются как base64, они загружаются независимо от того, нужны они для текущей страницы или нет.

Может ли предварительная загрузка улучшить ситуацию? Конечно. Можно предварительно загрузить изображение LCP и сократить время его загрузки, но раздувание потенциально некэшируемого HTML-кода встроенными ресурсами имеет и другие негативные последствия для производительности. На время первой отрисовки контента (FCP) также влияет этот шаблон. В версии страницы, где ничего не встроено, время FCP составляет примерно 2,7 секунды. В версии, где все встроено, время FCP составляет примерно 5,8 секунды.

Будьте очень осторожны со встраиванием кода в HTML, особенно ресурсов, закодированных в base64. В целом это не рекомендуется, за исключением очень маленьких ресурсов. Встраивайте как можно меньше кода, потому что слишком много — это игра с огнём.

Отображение разметки с помощью клиентского JavaScript

Нет никаких сомнений: JavaScript определенно влияет на скорость загрузки страниц . Разработчики полагаются на него не только для обеспечения интерактивности, но и для самой доставки контента. В некотором смысле это улучшает опыт разработчиков, но преимущества для разработчиков не всегда перерастают в преимущества для пользователей.

Один из способов обойти сканер предварительной загрузки — это рендеринг разметки с помощью клиентского JavaScript:

Диаграмма сетевого трафика WebPageTest, демонстрирующая базовую страницу с изображениями и текстом, полностью отрисованными на стороне клиента с помощью JavaScript. Поскольку разметка содержится в JavaScript, сканер предварительной загрузки не может обнаружить ни один из ресурсов. Все ресурсы дополнительно задерживаются из-за дополнительного времени на обработку и подключение к сети, необходимого для работы JavaScript-фреймворков.
Рис. 14: Диаграмма водопада сети WebPageTest для веб-страницы, отрисованной клиентом и запущенной в Chrome на мобильном устройстве через имитированное 3G-соединение. Поскольку контент содержится в JavaScript и использует фреймворк для рендеринга, ресурс изображения в разметке, отрисованной клиентом, скрыт от сканера предварительной загрузки. Эквивалентный опыт, отрисованный сервером, показан на рис. 9 .

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

Это несколько отклоняется от основной темы статьи, но последствия рендеринга разметки на стороне клиента выходят далеко за рамки обхода сканера предварительной загрузки. Во-первых, внедрение JavaScript для обеспечения работы интерфейса, который в нем не нуждается, приводит к ненужному времени обработки, которое может повлиять на время отрисовки до следующей отрисовки (INP) . Рендеринг чрезвычайно больших объемов разметки на стороне клиента с большей вероятностью приведет к длительным задачам по сравнению с тем же объемом разметки, отправляемым сервером. Причина этого — помимо дополнительной обработки, которую включает JavaScript — заключается в том, что браузеры передают разметку с сервера потоком и разбивают рендеринг на части таким образом, что это, как правило, ограничивает длительность задач. Разметка, отрисованная на стороне клиента, с другой стороны, обрабатывается как единая монолитная задача, что может повлиять на время отрисовки до следующей отрисовки страницы.

Решение этой проблемы зависит от ответа на следующий вопрос: есть ли причина, по которой разметка вашей страницы не может быть предоставлена ​​сервером, а не отрисована на стороне клиента? Если ответ на этот вопрос «нет», следует рассмотреть возможность использования серверного рендеринга (SSR) или статически сгенерированной разметки, поскольку это поможет сканеру предварительной загрузки обнаружить и оперативно получить важные ресурсы.

Если для добавления функциональности к некоторым частям разметки вашей страницы требуется JavaScript, вы все равно можете сделать это с помощью SSR, используя либо чистый JavaScript, либо гидратацию , чтобы получить преимущества обоих подходов.

Помогите сканеру предварительной загрузки помочь вам

Предварительная загрузка с помощью сканера — это высокоэффективная оптимизация браузера, которая помогает страницам загружаться быстрее при запуске. Избегая шаблонов, которые мешают ему обнаруживать важные ресурсы заранее, вы не только упрощаете разработку для себя, но и создаете лучший пользовательский опыт, который приведет к лучшим результатам по многим показателям, включая некоторые важные веб-аналитические параметры .

Подводя итог, вот что вам следует усвоить из этой статьи:

  • Сканер предварительной загрузки браузера — это вторичный HTML-парсер, который сканирует страницу раньше основного, если тот заблокирован, чтобы, при необходимости, обнаружить ресурсы, которые он может загрузить раньше.
  • Ресурсы, отсутствующие в разметке, предоставленной сервером при первоначальном запросе на навигацию, не могут быть обнаружены сканером предварительной загрузки. Способы обхода сканера предварительной загрузки могут включать (но не ограничиваются ими):
    • Внедрение ресурсов в DOM с помощью JavaScript, будь то скрипты, изображения, таблицы стилей или что-либо еще, что лучше было бы включить в первоначальную разметку с сервера.
    • Ленивая загрузка изображений или iframe в верхней части страницы с помощью JavaScript.
    • Отображение на стороне клиента разметки, которая может содержать ссылки на подресурсы документа, с использованием JavaScript.
  • Предварительно загруженный сканер сканирует только HTML. Он не проверяет содержимое других ресурсов, в частности CSS, которые могут содержать ссылки на важные элементы, включая LCP-кандидаты.

Если по какой-либо причине вы не можете избежать шаблона, который негативно влияет на способность сканера предварительной загрузки ускорять загрузку, рассмотрите подсказку ресурса rel=preload . Если вы используете rel=preload , протестируйте это в тестовых инструментах, чтобы убедиться, что это дает желаемый эффект. Наконец, не загружайте слишком много ресурсов предварительно, потому что, если вы расставите приоритеты для всего, ничего не останется в приоритете.

Ресурсы

Главное изображение взято с Unsplash , автор — Мохаммад Рахмани .