Трюк веб-оптимизации, который вы могли пропустить

1656536543 tryuk veb optimizaczii kotoryj vy mogli propustit

от Харнура Бандеша

ggUvHryjP1eaCueATOij6-v8FhYHQ059tc5Z

Вы когда-нибудь задумывались, почему страницы поиска Google или сайт Amazon загружаются очень быстро? Оставайтесь со мной, пока я познакомлю вас с концепцией, значительно улучшающей производительность страницы. Но сначала давайте рассмотрим некоторые концепции, ведущие к идее.

Анализ критического пути воспроизведения (CRP)

Прежде всего, давайте определим словарный запас, который мы будем использовать:

  1. Критический ресурс: Ресурс, который может блокировать исходное воспроизведение страницы
  2. Время до первого байта (TTFB): Измеряет продолжительность от того, как браузер делает HTTP-запрос до первого байта страницы, полученной браузером.

Оптимизация веб-производительности состоит в том, чтобы понять, что происходит на промежуточных этапах между получением файлов HTML, CSS и JavaScript и необходимой обработкой, чтобы превратить их в воспроизведенные пиксели – это критический путь воспроизведения (CRP).

Прежде чем страницы будут воспроизведены, браузер должен пройти все следующие шаги:

WQe1LRl6yEYWqRRCvl4EZQ62h1J-MWalcjsQ

Когда браузер впервые попадает на страницу, он загружает HTML файл. Затем она начинает создавать дерево DOM (объектная модель документа). Каждый тег в HTML представляет узел внутри дерева DOM, содержащий всю информацию о нем. Давайте примем пример, чтобы понять это.

Допустим, браузер получает такой HTML от сервера:

<html>
 <head>
   <meta name="viewport" content="width=device-width,initial-      scale=1">
   <link href=" rel="stylesheet">
   <title>Critical Path</title>
 </head>
 <body>
    <p>Hello <span>web performance</span> students!</p>
     <div><img src="awesome-photo.jpg"></div>
 </body>

Браузер превращает его в объект дерева под названием DOM как:

AqH7doxr-cbo5R-32GKdvZ5xYaCvGwwlMj4u
Источник: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model

Примечание: Процесс построения DOM является инкрементальным. Это основа идеи, ради которой я пишу статью.

Когда браузер создавал DOM, он столкнулся с a link тег в head раздел, ссылающийся на внешнюю таблицу стилей CSS.

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

body { font-size: 16px }
p { font-weight: bold } 
span { color: red } 
p span { display: none } 
img { float: right }

Затем браузер создает CSSOM (CSS Object Model):

GwlK2gSYqVlvagMKeEE8c0I7zRYFPAP9bL0H
Источник: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model

Деревья CSSOM и DOM объединяются для создания дерева визуализации. Затем дерево визуализации используется для вычисления макета каждого видимого элемента.

Вот как выглядит дерево визуализации:

qKI-Nmv3BuUQLW-9bG2u-fUxR3UMznJ-63wC
Источник: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction

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

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

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

Примечание: CSS блокирует визуализацию. До тех пор, пока CSSOM не будет создан, браузер не может перейти к шагу дерева визуализации. Поэтому нам нужно как можно скорее передать CSS файл в браузер, поэтому мы сохраняем все файлы link теги в head См. раздел.

Теперь давайте добавим JavaScript к нашему примеру:

<html>
 <head>
   <meta name="viewport" content="width=device-width,initial-scale=1">
   <link href=" rel="stylesheet">
   <title>Critical Path</title>
 </head>
 <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
    <script src="app.js"></script>
 </body>

По умолчанию выполнение JavaScript является блокировкой синтаксического анализатора. Когда браузер встречает a script тег в документе, он выполняет следующие действия:

1. Приостановить построение DOM

2. Загрузите файл

3. Передайте управление среде выполнения JavaScript

4. Дайте скрипту выполниться, прежде чем продолжить построение DOM

Браузер не знает, что скрипт планирует делать на странице, поэтому предполагает худший сценарий и блокирует синтаксический анализатор.

Подожди!!! Это не самый плохой случай, который может произойти во время разбора DOM. В последнем примере мы видим, что у нас есть внешние файлы CSS и JavaScript, которые нужно скачать браузеру.

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

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

SKjeC1Cwz5n179CwODwHkG8K0XWnfrRdLSyy
Источник: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp

CSS — это a демон для любой веб-страницы! Это также блокировка визуализации и блокировка анализа. Нам нужно быть очень аккуратными в обращении с ней.

Давайте рассмотрим некоторые методы оптимизации CRP.

Оптимизация CRP

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

Было бы хорошо, если бы нам не требовалось блокировать воспроизведение на этих ресурсах. «Типы медиа» и «медиа-запросы» CSS позволяют нам рассмотреть следующие случаи использования:

<link href=" rel="stylesheet">
<link href="print.css" rel="stylesheet" media="print">
<link href="other.css" rel="stylesheet" media="(min-width: 40em)">

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

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

Наконец, последняя таблица стилей будет исполнена браузером, если условие соответствует. Если условие не соответствует, браузер не блокирует воспроизведение.

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

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

Для этого мы отмечаем нашу script как async:
<script src=”app.js” async></script>

Добавление async ключевое слово к script тег сообщает браузеру не блокировать построение DOM, пока он ждет, пока скрипт станет доступным, что может значительно повысить производительность.

Еще один плюс async атрибут заключается в том, что script не блокируется, ожидая, пока CSSOM подготовится.

Скрипт Analytics является отличным примером для async атрибут как script никоим образом не изменяет DOM. Есть еще один атрибут для script теги, что есть defer. Вы можете узнать о defer посетив здесь.

И наконец – наступает вершина статьи, где я расскажу вам главный секрет – кроме оптимизации, указанной выше – что крупные компании применяют и творят чудеса…

Отправка HTML фрагментами с сервера

Посмотрите на приведенные ниже изображения и решите: как вы хотели бы, чтобы ваши веб-сайты отображались?

L0hvfXMCOkYqMTg1sMS9B8iSMgKSdOTYZv6n
Источник: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/

Вы получили ответ? Это, конечно, первый! Никто не любит так долго видеть пустую страницу. Гораздо лучше воспроизводить HTML фрагментами на веб-странице, что делают страницы поиска Google, Amazon и другие крупные гиганты.

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

После создания HTML на сервере он передается в обозреватель. Затем браузер начинает создавать DOM и выполняет все шаги CRP, как упоминалось ранее.

Следующая диаграмма поможет нам понять:

d6sq4uTavOf-X92c6UNvjssaPnANjwZdZVtj

Почему бы нам не оптимизировать время простоя браузера и не заставить его начать создание DOM, отправив готовый фрагмент HTML на сервер? Другими словами, мы можем удалять HTML фрагментами, когда они будут готовы, вместо того чтобы ждать, пока подготовится весь HTML. Это заставит браузер начать создание дерева DOM/CSSOM вместо ожидания простоя. Разве это не отличная идея!

Я надеюсь, что следующая диаграмма может больше прояснить эту идею:

tBQsjnYmgHkzdtbRxgjfhJPKe9p2pbXvOeJd

Страница на сервере разделена на фрагменты HTML. Теперь сервер вместо того, чтобы ждать, пока весь HTML подготовится, а затем передает его браузеру, будет посылать фрагменты HTML, когда они будут готовы на сервере. Это означает, что первые куски не будут ждать, пока два других подготовятся — они будут поданы браузеру в момент, когда они будут готовы на сервере.

Давайте примем пример, чтобы понять эту идею еще лучше. Ниже приведена страница поиска Google:

ZDbrdlHDORbGDPNNwunuhJcOPaDWzUjRXf0x

Теперь предположим, что мы попали на этот URL-адрес, и браузер отправляет запрос на сервер для обслуживания этой страницы. Сервер начинает создавать эту страницу и завершил создание HTML части A, но для части B ему нужно получить данные из какого-то источника, который займет некоторое время.

Теперь вместо того, чтобы ждать завершения части B, сервер удаляет заполненный HTML части A в браузере, чтобы он начал создавать DOM.

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

Это то, что Google действительно делает на своих страницах поиска! Даже Amazon сначала бросает свой заголовок, а остальная страница готовится на сервере.

Отправка HTML фрагментами также служит еще одной цели оптимизации. Как твой head тег первым достигает клиента, браузер инициирует CSS и другие запросы в теге. Это помогает браузеру загружать другие важные ресурсы, а остальное HTML готовит сервер.

Обычно время получения страницы с сервера составляет около 500 мс. Но типичное время получения первого фрагмента с сервера составляет примерно 20-30 мс. Вызов CSS, который должен быть инициирован через 500 мс, теперь начнется через 20–30 мс, что даст веб-странице ускорение примерно на 470–480 мс. Вы даже можете preload тяжелые изображения в head тег, который будет использоваться HTML-кодом, еще не поступающим с сервера, улучшая время загрузки страницы!

Теперь возникает вопрос: как отправить HTML фрагменты со стороны сервера.

Ну, у нас разные способы на разных языках. У нас есть метод под названием flush на Java, .NET и PHP. В Node.js нам нужно res.write() всякий раз, когда наш фрагмент HTML будет готов.

Примечание: браузер не выполняет повторные вызовы на сервер, чтобы получить все фрагменты. Все фрагменты HTML обслуживаются за один вызов к серверу.

Мой POC

Я создал POC из Node.js, Express и React, где компоненты React отображаются на Node.js и каждый компонент передается в браузер, как только его HTML будет подготовлен. Вы можете найти исходный код здесь.

Вы можете увидеть живую демонстрацию здесь.

В демонстрации вы можете увидеть ссылку. The Перейти на страницу без фрагментов ссылка переведет вас на страницу, на которой не была применена концепция фрагментации. The Перейти к странице с фрагментацией ссылка переведет вас на страницу, на которой была применена концепция фрагментации. Ниже приведены скриншоты страницы.

frsNGUPRgNiCxnmLLHq2EtqHqU0-CdIxYG-r
7wZFlc1VlwjTUXF9U-LtCIXKPCcDR3UV6-G0
2DAhtWjA4TUtSb3vWDU4pPUfOgdQZjGJ9MeG

Страница поделена на 4 части. В момент, когда часть A готовится на сервере, она передается в браузер, чтобы браузер мог начать создавать DOM.

Часть B создана с использованием данных API, что займет некоторое время. До тех пор браузер создает HTML части A в качестве конструкции DOM в постепенном процессе.

В момент, когда HTML раздел B готовится на сервере, он передается браузеру. История продолжается для части C и D.

Но вот одна загвоздка: даже перед отправкой части А я посылаю еще один фрагмент в браузер, который есть head тег HTML. В head Я предварительно скачал все тяжелые изображения баннеров в верхний и нижний колонтитул, а также сделал предварительное подключение и предварительную выборку DNS всех остальных изображений. Узнайте больше о предварительной загрузке, предварительной загрузке и предварительном подключении здесь.

The head тег также содержит ссылку на файл CSS. Теперь когда часть А готовится на сервере, браузер отправляет запрос на все ресурсы в файле head раздел, чтобы страница заполнялась быстрее, когда поступает HTML.

Тест производительности на обеих страницах проводился посредством расширения Lighthouse в Chrome. И результаты действительно обнадеживающие.

Тест был выполнен 10 раз на обеих страницах, и среднее значение всех значений отображается ниже:

fgPue6pGUhWo3BkX1d4Cv5POoxS59l3J8M9Y

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

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

Если вы хотите внести свою лепту в эту идею, или если вы считаете, что в ней можно сделать что-то лучшее, то, пожалуйста, расширьте репо, создайте новую ветку и подайте мне запрос на подъемник. Ниже приведены шаги для включения программы на локальном устройстве:

  1. Клон отсюда
  2. Установите Node в вашей системе
  3. Беги npm install внутри папки, где вы клонировали код
  4. Беги npm run dev сделать bundle.js файл
  5. Прекратите процесс и запустите npm start
  6. Приложение начнет работать 8080 порт

Пожалуйста, поделитесь этой статьей со своими друзьями, если она вам интересна. 🙂

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *