diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
commit | 074785cea106179cb3305637055ab0a009ca74f2 (patch) | |
tree | e6ae371cccd642aa2b67f39752a2cdf1fd4eb040 /files/ru/web/performance | |
parent | da78a9e329e272dedb2400b79a3bdeebff387d47 (diff) | |
download | translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.gz translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.bz2 translated-content-074785cea106179cb3305637055ab0a009ca74f2.zip |
initial commit
Diffstat (limited to 'files/ru/web/performance')
14 files changed, 1892 insertions, 0 deletions
diff --git a/files/ru/web/performance/critical_rendering_path/index.html b/files/ru/web/performance/critical_rendering_path/index.html new file mode 100644 index 0000000000..ae8a15756d --- /dev/null +++ b/files/ru/web/performance/critical_rendering_path/index.html @@ -0,0 +1,66 @@ +--- +title: Критические этапы рендеринга +slug: Web/Performance/Critical_rendering_path +tags: + - Performance +translation_of: Web/Performance/Critical_rendering_path +--- +<p><span class="seoSummary">Критические этапы рендеринга (Critical Rendering Path) - это последовательность шагов, которые выполняет браузер, когда преобразуется HTML, CSS и JavaScript в пиксели, которые вы видите на экране. Оптимизация этих шагов улучшает производительность рендера. Эти этапы включают в себя работу с <a href="/en-US/docs/Web/API/Document_Object_Model">Document Object Model </a>(DOM), <a href="/en-US/docs/Web/API/CSS_Object_Model">CSS Object Model </a>(CSSOM), деревом рендера (render tree) и компоновкой объектов (layout)</span></p> + +<p>Объектная модель документа DOM создается в тот момент, когда браузер парсит HTML. Этот HTML может запрашивать JavaScript, который может модифицировать DOM. HTML может запросить стили, которые участвуют в создании СSS Object Model. Движок браузера комбинирует эти две объектные модели, чтобы создать дерево рендера (render tree). Компоновка (layout) определяет размеры и позицию каждого элемента на странице. Как только компоновка определена - пиксели отрисовываются на экране.</p> + +<p>Оптимизация критичеческих этапов рендеринга улучшает время до первого рендера. Понимание и оптимизация этих этапов чрезвычайно важны для того, чтобы рендерить приложение с нужной частотой кадров (60 кадров в секунду, fps) и предоставить пользователю удобный, плавный интерфейс.</p> + +<h2 id="Понимание_этапов_CRP">Понимание этапов (CRP)</h2> + +<p>Производительность Web-приложений включает в себя запросы к серверу, получение ответов, загрузку, парсинг и выполнение скриптов, рендеринг, компоновку и отрисовку пикселей. </p> + +<p>Загрузка веб-страницы или приложения начинается с запроса HTML. Сервер возвращает HTML заголовке (headers) и некоторые данные. Браузер начинает парсить полученный ответ HTML, преобразуя полученные байты в DOM-дерево. Браузер создает новый запрос каждый раз, когда он находит ссылки на внешние ресурсы, будь то файлы стилей, скриптов или ссылки на изображения. Некоторые запросы являются блокирующими. Это означает, что пока такие запросы выполняются - другие запросы приостанавливается. Браузер продолжает парсить HTML и создавать DOM до тех пор, пока запрос на получение HTML не подходит к концу. После завершения парсинга DOM, браузер конструирует CSS модель. Как только эти модели сформированы, браузер строит дерево рендера (render tree), в котором вычисляет стили для каждого видимого элемента страницы. После формирования дерева происходит компоновка (layout), которая определяет положение и размеры элементов этого дерева. Как только этап завершён - страница рендерится. Или "отрисовывается" (paint) на экране.</p> + +<h3 id="Document_Object_Model">Document Object Model</h3> + +<p>Построение DOM инкрементально. Ответ в виде HTML превращается в токены, которые превращаются в узлы (nodes), которые формируют DOM дерево. Простейший узел начинается с startTag-токена и заканчивается токеном endTag. Узлы содержат всю необходимую информацию об HTML элементе, соответствующем этому узлу. Узлы (nodes) связаны с Render Tree с помощью иерархии токенов: если какой-то набор startTag и endTag-токенов появляется между уже существующим набором токенов, мы получаем узел (node) внутри узла (node), то есть получаем иерархию дерева DOM.</p> + +<p>Чем больше количество узлов (node) имеет приложение, тем дольше происходит формирование DOM tree, а значит дольше происходит обработка критических этапов рендеринга. Измеряйте! Несколько лишних узлов (node) не сделают погоды, но <a href="https://en.wiktionary.org/wiki/divitis">divitis</a> обязательно приведет к подвисаниям.</p> + +<h3 id="CSS_Object_Model">CSS Object Model</h3> + +<p>DOM несет в себе всё содержимое страницы. CSSOM содержит все стили страницы, то есть данные о том, как стилизовать DOM. CSSOM похож на DOM, но всё же отличается. Если формирование DOM инкрементально, CSSOM - нет. CSS блокирует рендер: браузер блокирует рендеринг страницы до тех пор, пока не получит и не обработает все CSS-правила. CSS блокирует рендеринг, потому что правила могут быть перезаписаны, а значит, необходимо дождаться построения CSSOM, чтобы убедиться в отсутствии дополнительных переопределений.</p> + +<p>У CSS имеются свои правила валидации токенов. Помните, что C в CSS означает "Cascade". CSS правила ниспадают каскадом. Иными словами, когда парсер преобразует токены в узлы (nodes), вложенные узлы наследуют стили от родительских. Инкрементальная обработка недоступна для CSS, потому что набор следующих правил может перезаписать предыдущие. Объектная модель CSS (CSSOM) строится по мере парсинга CSS, но она не может быть использована для построения дерева рендера (render tree), потому что может оказаться так, что следующий набор правил может сделать какой-либо из узлов дерева невидимым на экране. Это может привести к лишнему вызову компоновки и перерасчета стилей.</p> + +<p>Говоря о производительности селекторов (selector), наименее специфичные селекторы срабатывают быстрее. Например, <code>.foo {}</code> сработает быстрее <code>.bar .foo {}</code>. В первом случае, условно, понадобится одна операция, чтобы найти элемент <code>.foo</code>, во втором случае, сначала будут найдены все <code>.foo</code>, а<strong> </strong>потом<strong> браузер пройдет вверх</strong> по дереву в поисках родительского элемента <code>.bar</code>. Более специфичные селекторы требуют от браузера большего количества работы, но эти проблемы, вероятно, не стоят их оптимизации.</p> + +<p>Если вы измерите время, требуемое на парсинг CSS, вы будете удивлены тем, как быстро работают браузеры. Более специфичные правила более затратны, потому что требуют обхода большего числа узлов в DOM дереве, но эта дороговизна обходится довольно дёшево, особенно в сравнении с другими узкими местами производительности. <u>Сначала измеряйте. Потом оптимизируйте, если это действительно необходимо.</u> Вероятно, специфичность селекторов не то, что действительно затормаживает ваше приложение. Когда дело доходит до оптимизации CSS, улучшение производительность селекторов ускоряет рендеринг лишь на микросекунды. Существуют другие <a href="/en-US/docs/Learn/Performance/CSS_performance">пути оптимизации CSS</a>, такие как минификация, разделение CSS-файлов на разные файлы на освове media-queries.</p> + +<h3 id="Дерево_рендера_Render_Tree">Дерево рендера (Render Tree)</h3> + +<p>Дерево рендера охватывает сразу и содержимое страницы, и стили: это место, где DOM и CSSOM деревья комбинируются в одно дерево. Для построения дерева рендера браузер проверяет каждый узел (node) DOM, начиная от корневого (root) и определяет, какие CSS правила нужно присоединить к этому узлу. </p> + +<p>Дерево рендера охватывает только видимое содержимое. Например, секция head (в основном) не содержит никакой видимой информации, а потому может не включаться в дерево. Кроме того, если у какого-то узла стоит свойство <code>display: none</code>, оно так же не включается в дерево (как и потомки этого узла).</p> + +<h3 id="Компоновка_Layout">Компоновка (Layout)</h3> + +<p>В тот момент, когда дерево рендера (render tree) построено, становится возможным этап компоновки (layout). Компоновка зависит от размеров экрана. Этот этап определяет, где и как на странице будут спозиционированы элементы и каковы связи между элементами.</p> + +<p>Что насчет ширины элемента? Блочные элемент по определению имеют ширину в 100% от ширины их родителя. Элемент с шириной в 50% будет иметь ширину в два раза меньше родительской. Если не указано иного, элемент body имеет ширину 100%, то есть 100% ширины родителя - видимой области viewport (окна документа).</p> + +<p>Мета тэг viewport, который вы можете указать в Head страницы, определяет ширину видимой области и влияет на компоновку. Без этого тэга браузеры используют ширину "по умолчанию", которая обычно составляет 960px. В браузерах, открывающихся по умолчанию в полноэкранном режиме, например, в браузере телефона, установка тега <code><meta name="viewport" content="width=device-width"></code> установит ширину видимой области в 100% от ширины экрана устройства, вместо того, чтобы использовать ширину по умолчанию. Эта ширина (<code>device-width)</code> изменяется каждый раз, когда пользователь поворачивает телефон. Это приводит к запуску этапа компоновки. Равно как и при изменении размеров окна в обычном браузере.</p> + +<p>На производительность компоновки (layout) непосредственно влияет DOM - чем больше узлов (nodes) в вашем документе, тем больше времени понадобится на перерасчет позиций и размеров всех элементов. Компоновка может стать узким местом, ведущим к зависаниям, особенно если выполняет одновременно со скроллом или другой анимацией. И хотя задержка 20мс при загрузке или переориентации экрана может быть приемлемой, это все равно может привести к подвисаниям при анимации и скролле. Каждый раз, когда дерево рендера (render tree) модифицируется, например, из-за добавления узла (node), его модификации или при изменении стилей box-модели, запускается компоновка.</p> + +<p>Для уменьшения частоты и продолжительности этого этапа, группируйте обновления экрана и избегайте анимации свойств, связанных с box-моделью элементов.</p> + +<h3 id="Отрисовка_Paint">Отрисовка (Paint)</h3> + +<p>Последний этап в нашем списке - отрисовка (paint) пикселей на экране. Когда дерево рендера (render tree) создано, компоновка (layout) произошла, пиксели могут быть отрисованы. При первичной загрузке документа (onload) весь экран будет отрисован. После этого только необходимые к обновлению части экрана будут перерисовываться, так как браузер старается оптимизировать процесс отрисовки, избегая ненужной работы. Так, если у вас в документе есть два элемента, перерисовываться будет только тот, который вы изменили. Время отрисовки зависит от того, какой тип обновления применился к дереву рендера (render tree). И хотя отрисовка - это очень быстрый процесс, и он, вероятно, слабо влияет на производительность, очень важно помнить, что оба этапа - компоновка (layout) и отрисовка (paint) должны работать сообща и укладываться в частоту обновления кадров. Каждое CSS-свойство, применяемое к любому узлу (node) увеличивает время отрисовки, но полное удаление стиля, способное сэкономить вам 0.001мс, вряд ли даст вам желаемый результат, но зато с легкостью ухудшит пользовательский опыт. <strong>Помните - сначала нужно измерять, а потом оптимизировать только необходимое!</strong></p> + +<h2 id="Оптимизация_CRP">Оптимизация CRP</h2> + +<p>Улучшайте загрузку страницы с помощью приоритезации ресурсов, с помощью контролирования порядка, в котором они грузятся и с помощью уменьшения размеров файлов. Главные подсказки здесь:</p> + +<ol> + <li>Уменьшайте количество критических ресурсов, откладывая их загрузку, помечая их как async и/или группируя их;</li> + <li>Оптимизируйте количество необходимых запросов, а так же размеры файлов;</li> + <li>Оптимизируйте порядок так, чтобы критические ресурсы загружались в первую очередь, сокращая таким образом длину критических этапов рендеринга.</li> +</ol> diff --git a/files/ru/web/performance/css_javascript_animation_performance/index.html b/files/ru/web/performance/css_javascript_animation_performance/index.html new file mode 100644 index 0000000000..264fc1ea9b --- /dev/null +++ b/files/ru/web/performance/css_javascript_animation_performance/index.html @@ -0,0 +1,80 @@ +--- +title: Производительность CSS и JavaScript анимации +slug: Web/Performance/CSS_JavaScript_animation_performance +tags: + - CSS + - FPS + - Transitions + - requestAnimationFrame + - Анимация + - Производительность +translation_of: Web/Performance/CSS_JavaScript_animation_performance +--- +<p class="summary">Анимация является критичным инструментов для улучшения пользовательнского опыта во многих приложениях. Существует много путей создания анимации в web, например, основанные на CSS-свойствах {{cssxref("transition","transitions")}}/{{cssxref("animation","animations")}} или на JavaScript (using {{domxref("Window.requestAnimationFrame","requestAnimationFrame()")}}). В этой статье мы проанализируем производительность CSS и JavaScript анимаций и сравним их.</p> + +<h2 id="CSS_transition_и_animation">CSS transition и animation</h2> + +<p>Оба этих свойства могут использоваться для создания анимации. Каждое из них имеет своё специфичное назначение:</p> + +<ul> + <li>CSS {{cssxref("transition","transitions")}} предоставляет простой способ создать анимацию, которая происходит при переходе от текущего состояния к конечному, например, переход от обычной кнопки к кнопке в состоянии hover. Даже если элемент в середине перехода от одного стиля к другому, новый эффект transition стартует немедленно, вместо того, чтобы дожидаться, пока запущенный ранее эффект завершится. Подробнее здесь: <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transitions">Использование CSS transitions</a>.</li> + <li>CSS {{cssxref("animation","animations")}}, с другой стороны, позволяет разработчикам создавать анимацию, основанную на ключевых кадрах (keyframes), которые указывают этапы, которые должна пройти анимация от начального до финального состояния. CSS animation состоит из двух компонент: описание свойства, которое указывает на анимацию, а так же набор ключевых кадров, которые указывают начальное, финальное и промежуточные состояния элемента. Подробнее здесь: <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_animations">Использование CSS animations</a>.</li> +</ul> + +<p>Если говорить о производительности - между этими двумя подходами нет разницы. Оба подхода основаны на одном и том же механизме, которые описаны далее.</p> + +<h2 id="requestAnimationFrame">requestAnimationFrame</h2> + +<p>API {{domxref("Window.requestAnimationFrame","requestAnimationFrame()")}} предоставляет эффективный способ создания анимаций в JavaScript. Функция (callback), которую вы передаете в этот метод, будет вызываться перед каждой следующей отрисовкой нового фрейма. Главное отличие от {{domxref("WindowTimers.setTimeout","setTimeout()")}}/{{domxref("WindowTimers.setInterval","setInterval()")}} в том, что здесь вам не нужно указывать время, через которое функция запустится. <code>requestAnimationFrame()</code> работает гораздо эффективнее, учитывая частоту кадров и производительность системы. Разработчики могут создавать анимацию, просто изменяя стили элемента каждый раз, когда происходит подготовка нового кадра (или когда обновляется полотно Canvas или в других случаях).</p> + +<div class="note"> +<p><strong>Заметка</strong>: Подобно CSS transition и animation, <code>requestAnimationFrame()</code> приостанавливает работу, когда текущий таб переводится в фоновый режим (например, при смене фокуса)</p> +</div> + +<p>Для подробностей ознакомьтесь с <a href="https://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/">анимирование с JavaScript: от setinterval до requestAnimationFrame</a>.</p> + +<h2 id="Сравнение_производительности_transitions_и_requestAnimationFrame">Сравнение производительности:<br> + transitions и requestAnimationFrame</h2> + +<p>По факту, в большинстве случаев, производительность анимаций CSS практически идентична анимациям на JavaScript. По крайней мере в Firefox. Авторы некоторых JavaScript библиотек для анимации, например GSAP или Velocity.JS, даже берутся утверждать, что их решения могут работать быстрее, чем аналогичные решения на CSS. Такое возможно, потому что CSS transitions/animations просто заново вычисляют стили элементов в основном потоке процессора сразу перед тем, как срабатывает событие repaint, что примерно то же самое, что вычислять стили заново с помощью <code>requestAnimationFrame()</code>. Если обе анимации выполняются в одном потоке, то разницы в производительности не будет.</p> + +<p>В следующей секции мы пройдемся по тестам производительности, используя Firefox, чтобы увидеть, какие методы анимации работают эффективнее.</p> + +<h3 id="Включение_измерения_частоты_кадров_FPS">Включение измерения частоты кадров FPS</h3> + +<p>Для начала нам нужно включить инструменты измерения частоты кадров (FPS Tools), чтобы иметь возможность видеть текущую частоту кадров</p> + +<ol> + <li>В поле ввода URL наберите <em>about:config</em>; Нажмите на кнопку <em>I’ll be careful, I promise!, чтобы войти на страницу конфигурации</em>.<br> + <img alt="" src="https://mdn.mozillademos.org/files/11137/Pic1.png" style="height: 349px; width: 600px;"><br> + </li> + <li>В поле поиска введите <code>layers.acceleration.draw-fps</code>.</li> + <li>Нажмите два раза на ячейку, чтобы присвоить значение <code>true</code>. Теперь вы видите три розовых блока в верхнем левом углу окна. Первый блок указывает FPS.<br> + <img alt="" src="https://mdn.mozillademos.org/files/11139/Pic2.png" style="height: 215px; width: 562px;"></li> +</ol> + +<h3 id="Запуск_теста">Запуск теста</h3> + +<p>Для начала, в нашем тесте мы будем анимаировать 1000 элементов {{htmlelement("div")}} с помощью CSS.</p> + +<p><span style="line-height: 16.7999992370605px;">{{JSFiddleEmbed("https://jsfiddle.net/zt94oew2/1/","","480")}}</span></p> + +<p>Нажав на кнопку, вы можете переключить метод анимации на <code>requestAnimationFrame()</code>.</p> + +<p>Попробуйте запустить оба метода и сравнить FPS. Скорее всего, вы увидите, что частота кадров отличается - анимации с CSS заметно быстрее. В следующей главе мы разберём - почему.</p> + +<h3 id="Анимация_вне_основного_потока_процесса">Анимация вне основного потока процесса</h3> + +<p>Браузерный JavaScript является строго однопоточным языком, то есть он не может одновременно работать над двумя задачами. В этом кроется проблема анимации с помощью JavaScript. Выполняя такую анимацию, вы занимаете процессор, который мог бы в это время заниматься другими функциями. В противоположность этому, CSS анимации могут быть выделены в отдельный поток, то есть при выполнении таких анимаций браузер не блокирует выполнение других процессов. </p> + +<p>Для того, чтобы выделить анимацию CSS в отдельный процесс, нам нужно убедиться, что изменяемые свойства не запускают этапы reflow/repaint (подробнее здесь: <a href="http://csstriggers.com/">CSS triggers</a>). Если изменяемые CSS свойства не делают этого, то мы можем вынести операции по вычислению стилей в отдельный поток. Наиболее известное свойство - это CSS Transform, которое выводит элемент в отдельный <a href="https://wiki.mozilla.org/Gecko:Overview#Graphics">слой</a>. Если элемент представляет из себя отдельный слой, то вычисление каждого следующего кадра может быть сделано на графическом процессоре (GPU). Это радикально улучшает производительность, особенно на мобильных устройства. Подробности здесь: <a href="https://wiki.mozilla.org/Platform/GFX/OffMainThreadCompositing">OffMainThreadCompositing</a>.</p> + +<p>Вы можете отключить выведение анимации в отдельный поток, чтобы посмотреть, как эта особенность влияет на FPS. Для этого в настройках Firefox найдите флаг <code>layers.offmainthreadcomposition.async-animations</code>. И переключите его в <code>false</code>.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/11141/Pic3.png" style="height: 210px; width: 536px;"></p> + +<p>После выключения этой опции вы увидите, что FPS при использовании CSS стал таким же, как и при использовании JS.</p> + +<h2 id="Итог">Итог</h2> + +<p>Браузеры способы оптимизировать рендеринг не только программно, но и аппаратно. В целом, вам нужно стараться использовать CSS transitions/animations везде, где это возможно. Если же ваши анимации действительно сложны - помните, что писать анимацию на JavaScript нужно только с использованием <code>requestAnimationFrame()</code> .</p> diff --git a/files/ru/web/performance/dns-prefetch/index.html b/files/ru/web/performance/dns-prefetch/index.html new file mode 100644 index 0000000000..56002153ce --- /dev/null +++ b/files/ru/web/performance/dns-prefetch/index.html @@ -0,0 +1,70 @@ +--- +title: Использование dns-prefetch +slug: Web/Performance/dns-prefetch +tags: + - Web Performance + - dns-prefetch + - preconnect +translation_of: Web/Performance/dns-prefetch +--- +<p><span class="seoSummary"><code><strong>DNS-prefetch</strong></code> (предзагрузка DNS) - это попытка определить IP адрес по имени домена до того, как ресурс с этого домена будет фактически запрошен. Это может быть загрузчик файлов, который используется позже или ссылка, по которой, вероятно, перейдёт пользователь. </span></p> + +<h2 id="Зачем_использовать_dns-prefetch">Зачем использовать dns-prefetch?</h2> + +<p>Бывают случаи, когда в вашем приложении использются ссылки на домены, отличные от основного домена приложения. Например, внутри вашего приложения на "a.com" есть ссылка на домен "b.org". Для того, чтобы пройти по этой ссылке, пользовательский клиент должен сначала выяснить, какой адрес в интернете соответствует доменному имени "b.org". Этот процесс называется <code>DNS resolution.</code> И хотя механизмы кеширования DNS помогают сократить время запросов, DNS Resolution заметно влияет на время ожидания запроса из-за того, что первый клиентский запрос уходит сначала на DNS сервера и дожидается ответа от них. Для приложений, которые открывают соединения ко многим сторонним доменам, влияние DNS Resolution может сильно уменьшить производительность загрузки.</p> + +<p><code>dns-prefetch</code> помогает разработчикам замаскировать ожидание DNS resolution. <a href="/en-US/docs/Web/HTML/Element/link">HTML <code><link></code> элемент</a> предлагает подобный функционал с помощью атрибута <a href="/en-US/docs/Web/HTML/Attributes/rel"><code>rel</code></a>, значение которого может содержать <code>dns-prefetch</code>. В этом случае, предзагрузка DNS произойдет для домена, указанного в атрибуте <a href="/en-US/docs/Web/HTML/Attributes">href</a>:</p> + +<h2 id="Синтаксис">Синтаксис</h2> + +<pre class="brush: html notranslate"><link rel="dns-prefetch" href="https://fonts.gstatic.com/" > +</pre> + +<h2 id="Примеры">Примеры</h2> + +<pre class="brush: html notranslate"><html> + <head> + <link rel="dns-prefetch" href="https://fonts.gstatic.com/"> + <!-- and all other head elements --> + </head> + <body> + <!-- your page content --> + </body> +</html></pre> + +<p>Вы должны помещать <code>dns-prefetch</code> подсказки в элемент <a href="/en-US/docs/Web/HTML/Element/head"><code><head></code></a> для каждого уникального стороннего домена, с которого могут быть запрошены ресурсы, но нужно держать некоторые детали в голове.</p> + +<h2 id="Лучшие_практики">Лучшие практики</h2> + +<p id="Three_things_to_keep_in_mind">Необходимо учитывать 3 вещи:</p> + +<p><strong>Во-первых,</strong> <code>dns-prefetch</code> эффективен только для выполнения DNS запросов не сторонние <a href="/en-US/docs/Web/HTTP/CORS">cross-origin</a> домены, поэтому следует избегать этой инструкции при попытке загрузить ресурсы с текущего домена. Связано это с тем, что IP вашего домена уже был определён к тому времени, когда браузер увидел эту инструкцию.</p> + +<p><strong>Во-вторых,</strong> существует возможность добавить <code>dns-prefetch</code> (и другие подсказки) как <a href="/en-US/docs/Web/HTTP/Headers">HTTP заголовок</a> с помощью <a href="/en-US/docs/Web/HTTP/Headers/Link">HTTP Link field</a>:</p> + +<pre class="brush: unix notranslate">Link: <https://fonts.gstatic.com/>; rel=dns-prefetch</pre> + +<p><strong>В третьих, </strong> хорошей практикой считается использование <code>dns-prefetch</code> в паре с <code>preconnect</code>. В то время, как <code>dns-prefetch</code> срабатывает только при DNS поиске, <code>preconnect</code> устанавливает соединение к нужному серверу. Этот процесс включает в себя DNS resolution, установку TCP соединения и установление безопасного соединения (<a href="/en-US/docs/Glossary/TLS">TLS</a> рукопожатие), если оно доступно. Комбинирование этих двух инструкций дает возможность ещё больше сократить время ожидания для кросс-доменных запросов. Вы можете использовать их вместе таким образом:</p> + +<pre class="brush: html notranslate"><link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin> +<link rel="dns-prefetch" href="https://fonts.gstatic.com/"> +</pre> + +<div class="blockIndicator note"> +<p><strong>Заметка: </strong> если приложению необходимо установить соединение со множеством доменов, использование preconnect контрпродуктивно. <code>preconnect</code> лучше использовать для наиболее критических соединений. Для менее важных достаточно использовать <code><link rel="dns-prefetch"></code> для сокращения времени DNS запроса.</p> +</div> + +<p>В совместном использовании этих двух техник есть логика. Она заключается в том, что dns-prefetch поддерживается большим количеством браузеров, чем preconnect. Клиенты, которые ещё не поддерживают preconnect, все ещё будут получать бонусы от работы dns-prefetch. Так как эти инструкции относятся к HTML, они очень толерантны к ошибкам. Если какой-то устаревший браузер встречает dns-prefetch, ваш сайт не сломается. Вы просто не получите улучшений от этой инструкции.</p> + +<p>Некоторые ресурсы, например, шрифты, загружаются в анонимном режиме. В подобных случаях вы должны указывать <a href="/en-US/docs/Web/HTML/CORS_settings_attributes">crossorigin</a> атрибут с инструкцией preconnect. Если вы пропустите её, то браузер выполнит только DNS запрос.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/HTML/Element/link"><link></a></li> + <li><a href="/en-US/docs/Web/HTML/Attributes/rel">HTML атрибут: rel</a></li> + <li><a href="/en-US/docs/Web/HTML/CORS_settings_attributes">crossorigin</a></li> + <li><a href="/en-US/docs/Web/HTTP/CORS">Cross-Origin Resource Sharing (CORS)</a></li> + <li><a href="/en-US/docs/Web/HTTP/Headers">HTTP заголовки</a></li> + <li><a href="/en-US/docs/Web/HTTP/Headers/Link">HTTP заголовок </a><a href="/en-US/docs/Web/HTTP/Headers/Link" title="The HTTP Link entity-header field provides a means for serialising one or more links in HTTP headers. It is semantically equivalent to the HTML <link> element.">Link</a></li> +</ul> diff --git a/files/ru/web/performance/how_browsers_work/index.html b/files/ru/web/performance/how_browsers_work/index.html new file mode 100644 index 0000000000..a2e16dd970 --- /dev/null +++ b/files/ru/web/performance/how_browsers_work/index.html @@ -0,0 +1,218 @@ +--- +title: Как работают браузеры +slug: Web/Performance/How_browsers_work +tags: + - Browsers + - DNS Lookup + - SSL/TLS Handshake + - TCP handshake + - Критический путь рендеринга + - Навигация + - Производительность + - загрузка страницы + - композиция + - отрисовка + - рендеринг +translation_of: Web/Performance/How_browsers_work +--- +<p>Пользователи хотят использовать приложения, в которых загрузка контента происходит быстро, а взаимодействие - плавно. Разработчик должен стараться оптимизировать своё приложение как минимум по этим двум показателям.</p> + +<p><span class="seoSummary">Чтобы понять, как улучшить производительность и ощущаемую пользователем производительность (User Perceived Performance, UPP), вам необходимо понимать, как работают браузеры.</span></p> + +<h2 id="Обзор">Обзор</h2> + +<p>Быстрые приложения дают лучшие ощущения. Пользователи ожидают, что приложение будет грузиться быстро, а взаимодействие с ним будет плавным.</p> + +<p>Две главных проблемы в производительности - это проблема скорости сети и проблема однопоточности браузеров.</p> + +<p>Сетевые задержи - это главная проблема, которую нужно преодолеть при достижении быстрой загрузки. Чтобы ускорить загрузку разработчик должен посылать запрошенные данные как можно быстрее или, на худой конец, сделать вид, что они отправляются очень быстро. Сетевые задержки - это время, которое требуется для передачи данных от источника к браузеру. Производительность здесь - это то, что делает загрузку страницу как можно более скорой.</p> + +<p>В большинстве своём браузеры рассматриваются как однопоточные приложения. Чтобы достичь плавности взаимодействия, разработчик должен обеспечивать производительность во всём, начиная от плавного скроллинга, до быстрой реакции на нажатие экрана. Время рендера - это ключевое понятие. Разработчик должен обеспечить такую работу приложения, чтобы все его задачи могли быть выполнены достаточно быстро. В таком случае процессор будет свободен для обработки пользовательского ввода. Для решения проблемы однопоточности вы должны понять природу браузеров и научиться разгружать основной поток процесса там, где это возможно и допустимо.</p> + +<h2 id="Навигация">Навигация</h2> + +<p>Навигация - это первый этап при загрузке приложения. Он происходит каждый раз, когда пользователь запрашивает страницу, вводя URL в адресную строку браузера, нажимает на ссылку, отправляет заполненные поля формы и выполняет некоторые другие действия.</p> + +<p>Одна из задач разработчика - сократить время, которое требуется приложению, чтобы этап навигации завершился. В идеальных условиях это обычно не занимает много времени, но задержки сети и ширина канала - препятствия, которые приводят к задержкам загрузки приложения.</p> + +<h3 id="DNS_запрос">DNS запрос</h3> + +<p>Первый шаг навигации к странице - это поиск места, откуда нужно запрашивать данные. Если вы переходите на <code>https://example.com</code>, браузер грузит HTML-код страницы с IP-адреса <code>93.184.216.34</code>. Если вы никогда ранее не были на этом сайте, произойдет поиск DNS записи.</p> + +<p>Ваш браузер запрашивает DNS запись. Как правило, запрос содержит имя сервера, который должен быть преобразован в IP-адрес. Ответ на этот запрос какое-то время будет сохранён в кэше устройства, чтобы его можно было быстро получить при следующем запросе к тому же серверу.</p> + +<p>DNS запрос обычно требуется совершить лишь единожды при загрузке страницы. Однако, DNS запросы должны быть выполнены для каждого уникального имени хоста, который запрашивается страницей. Скажем, если ваши шрифты, картинки, скрипты, реклама или счетчики аналитики находятся на разных доменах, DNS запрос будет осуществлен для каждого из них.</p> + +<p><img alt="Mobile requests go first to the cell tower, then to a central phone company computer before being sent to the internet" src="https://mdn.mozillademos.org/files/16743/latency.jpg" style="height: 281px; width: 792px;"></p> + +<p>Это может быть проблемой с точки зрения производительности, особенно для мобильных сетей. Когда пользователь находится в мобильной сети, каждый DNS запрос должен пройти от мобильного устройства до сотовой вышки, а уже оттуда дойти до авторитетного DNS-сервера. Расстояние и помехи между телефоном, вышкой и сервером имён могут значительно увеличить задержку.</p> + +<h3 id="TCP_Рукопожатие_Handshake">TCP Рукопожатие (Handshake)</h3> + +<p>В тот момент, когда IP адрес становится известен, браузер начинает установку соединения к серверу с помощью рукопожатия {{glossary('TCP handshake','TCP three-way handshake')}}. Этот механизм спроектирован так, чтобы два устройства, пытающиеся установить связь, могли обменяться параметрами соединения, прежде чем приступать к передаче данных. Чаще всего - через защищённое соединение {{glossary('HTTPS')}}.</p> + +<p>Трёхэтапное рукопожатие TCP - это техника, очень часто упоминаемая как "SYN-SYN-ACK" (<code>SYN, SYN-ACK, ACK</code>, если быть точнее), т.к. при установке соединения передаются 3 сообщения. Это означает, что прежде чем установится соединение, браузер должен обменяться ещё тремя сообщениями с сервером.</p> + +<h3 id="TLS_Переговоры_Negotiation">TLS Переговоры (Negotiation)</h3> + +<p>Для установки безопасных соединений с использованием HTTPS требуется ещё одно рукопожатие. На этот раз - {{glossary('TLS')}} переговоры. На этом шаге определяется, какой шифр будет использоваться для шифрования соединения, удостоверяется надёжность сервера и устанавливается безопасное соединение. Этот шаг также требует несколько дополнительных сообщений, которыми должны обменяться сервер и браузер, прежде чем данные будут посланы.</p> + +<p><img alt="The DNS lookup, the TCP handshake, and 5 steps of the TLS handshake including clienthello, serverhello and certificate, clientkey and finished for both server and client." src="https://mdn.mozillademos.org/files/16746/ssl.jpg" style="height: 412px; width: 729px;"></p> + +<p>И хотя обеспечение безопасности соединения снижает скорость загруки приложения, безопасное соединение стоит затрат на него, так как в этом случае данные не могут быть дешифрованы третьим лицом.</p> + +<p>После обмена восемью сообщениями, браузер, наконец, достигает всех условий, чтобы сделать запрос.</p> + +<h2 id="Ответ_на_запрос">Ответ на запрос</h2> + +<p>Как только мы установили соединение с веб-сервером, браузер отправляет инициирующий <a href="/en-US/docs/Web/HTTP/Methods">HTTP <code>GET</code> запрос</a> от имени пользователя. Чаще всего запрашивается HTML файл. В момент, когда сервер получает запрос, он начинает ответ с посылки заголовков ответа и содержимым HTML-файла.</p> + +<pre class="brush: html notranslate"><!doctype HTML> +<html> + <head> + <meta charset="UTF-8"/> + <title>My simple page</title> + <link rel="stylesheet" src="styles.css"/> + <script src="myscript.js"></script> +</head> +<body> + <h1 class="heading">My Page</h1> + <p>A paragraph with a <a href="https://example.com/about">link</a></p> + <div> + <img src="myimage.jpg" alt="image description"/> + </div> + <script src="anotherscript.js"></script> +</body> +</html></pre> + +<p>Этот ответ содержит в себе первый байт полученных данных. Время до первого байта ({{glossary('Time to First Byte')}}, TTFB) - это время между моментом когда пользователь отправил запрос, скажем, нажав на ссылку, и моментом получения первого пакета данных HTML. Первый пакет обычно содержит 14КБ данных.</p> + +<p>В примере выше ответ значительно меньше, чем 14КБ; скрипты и стили, перечисленные в ответе, не будут запрошены, пока браузер не обработает ответ. Процесс обработки ответа - парсинг - мы обсудим отдельно.</p> + +<h3 id="TCP_медленный_старт_правило_14kb">TCP медленный старт / правило 14kb</h3> + +<p>Объём первого пакета данных - всегда 14KB. Это часть спецификации {{glossary('TCP slow start')}} - алгоритма, который балансирует скорость соединения. Такое правило позволяет постепенно, по мере необходимости, увеличивать размеры передаваемых данных, пока не будет определена максимальная ширина канала.</p> + +<p>В алгоритме {{glossary('TCP slow start')}} каждый следующий отправленный сервером пакет увеличивается в размере в два раза. Например, размер второго пакета будет около 28КБ. Размер пакетов будет увеличиваться до тех пор, пока не достигнет какого-то порогового значения или не упрется в проблему переполнения.</p> + +<p><img alt="TCP slow start" src="https://mdn.mozillademos.org/files/16754/congestioncontrol.jpg" style="height: 412px; width: 729px;"></p> + +<p>Если вы когда-то слышали о правиле 14КБ, то должны понимать, что оптимизация производительности загрузки должна учитывать ограничения этого начального запроса. Медленный старт TCP позволяет плавно ускорять передачу данных так, чтобы избежать проблемы переполнения, когда много данных ожидают отправки, но не отправляются из-за ограничений ширины канала.</p> + +<h3 id="Контроль_переполнения">Контроль переполнения</h3> + +<p>Любое соединение имеет ограничения, связанные с аппаратной и сетевой системами. Если сервер отправит слишком много пакетов за раз - они могут быть отброшены. Для того, чтобы избежать таких проблем, браузер должен реагировать на получение пакетов и подтверждать, что он получает их. Такой ответ-подтверждение называется Aknowledgements (ACK). Если из-за ограничений соединения браузер не получит данных, то он не пошлёт подтверждений ACK. В этом случае, сервер зарегистрирует, что какие-то пакет не дошли и пошлёт их заново, что приведет к лишней работе сервера и дополнительной нагрузке сети.</p> + +<h2 id="Парсинг">Парсинг</h2> + +<p>Как только браузер получает первый кусочек данных, он сразу начинает обрабатывать получаемую информацию. Эта обработка называется "Парсинг" ({{glossary('speculative parsing', 'Parsing')}}). Во время парсинга получаемые данные преобразуются в {{glossary('DOM')}} и {{glossary('CSSOM')}}, которые напрямую участвуют в отрисовке.</p> + +<p>DOM (Объектная модель документа) - это внутреннее представление разметки HTML. Браузер предоставляет доступ к манипуляции объектами этой модели через разные JavaScript API.</p> + +<p>Даже если ответ на запрос больше 14КБ, браузер все равно начинает парсинг данных и пытается отрисовать страницу с теми данными, которые уже доступны. Именно поэтому при оптимизации производительности очень важно включать в инициирующий 14КБ ответ все необходимые для рендера данные - так браузер сможет быстрее начать формирование страницы. Однако, прежде чем что-либо появится на экране, HTML, CSS и JavaScript должны быть обработаны.</p> + +<h3 id="Построение_дерева_объектной_модели_документа">Построение дерева объектной модели документа</h3> + +<p>Мы уже рассказывали о пяти шагах в <a href="/ru/docs/Web/Performance/Critical_rendering_path">критическом пути рендеринга</a>.</p> + +<p>Первый шаг - это обработка разметки HTML и построение дерева DOM. Обработка HTML включает в себя токенизацию и построение дерева. HTML-токены состоят из тегов старта и финиша, а также атрибутов. Если документ сформирован правильно, его обработка прямолинейна и быстра. Парсер (обработчик) преобразует входящие токены в документ и строит дерево документа.</p> + +<p>Объектная модель документа (DOM) описывает содержимое документа. Элемент <code><a href="/en-US/docs/Web/HTML/Element/html"><html></a></code> - это первый тег и корневой элемент дерева документа. Дерево отражает связи и иерархию между разными тегами. Теги, вложенные в другие теги являются детьми. Чем больше существует узлов в дереве, тем сложнее это дерево построить.</p> + +<p><img alt="The DOM tree for our sample code, showing all the nodes, including text nodes." src="https://mdn.mozillademos.org/files/16759/DOM.gif" style="height: 689px; width: 754px;"></p> + +<p>Когда парсер находит неблокирующие ресурсы (например, изображения), браузер отправляет запрос на загрузку ресурсов, но сам продолжает обработку. Обработка может продолжаться когда обнаружена ссылка на CSS файл, но если обнаружен <code><script></code>, особенно если он без параметров <code>async</code> или <code>defer</code> - такой скрипт считается блокирующим и приостанавливает обработку HTML до завершения загрузки скрипта. Несмотря на то, что сканер предзагрузки (о нём ниже) браузера может находить и запрашивать такие скрипты заранее, сложные и объемные скрипты всё ещё могут стать причиной заметных задержек загрузки страницы.</p> + +<h3 id="Сканер_предзагрузки">Сканер предзагрузки</h3> + +<p>Построение дерева DOM занимает весь поток процесса. Так как это явно узкое место в производительности, был создан особый сканер предзагрузки. Он обрабатывает доступное содержимое документа и запрашивает высокоприоритетные ресурсы (CSS, JavaScript и шрифты). Благодаря этому сканеру нам не нужно ждать, пока парсер дойдет до конкретного места, где вызывается ресурс. Он запрашивает и получает эти данные заранее, в фоновом режиме, так что когда основной поток HTML-парсера доходит до запроса ресурса, высока вероятность, что ресурс уже запрошен или находится в процессе загрузки. Оптимизации, которые даёт этот сканер, уменьшают время блокирования рендера.</p> + +<pre class="brush:html notranslate"><link rel="stylesheet" src="styles.css"/> +<script src="myscript.js" <strong>async</strong>></script> +<img src="myimage.jpg" alt="image description"/> +<script src="anotherscript.js" <strong>async</strong>></script> +</pre> + +<p>В примере выше основной поток обрабатывает HTML и CSS. В то же время, сканер предзагрузки находит скрипты и изображение и начинает их загрузку. Чтобы сделать скрипт неблокирующим, добавьте атрибут <code>async</code> или, в случае, если порядок загрузки скриптов не важен, атрибут <code>defer</code>.</p> + +<div class="blockIndicator note"> +<p>Ожидание получения CSS не блокирует парсинг HTML, но он блокирует JavaScript, потому что JavaScript часто используется для выборки узлов документа по CSS-селекторам.</p> +</div> + +<h3 id="Построение_модели_стилей_CSSOM">Построение модели стилей CSSOM</h3> + +<p>Второй шаг при прохождении критического пути рендеринга - это обработка CSS и построение CSSOM дерева. CSSOM (объектная модель CSS) похожа на DOM. И DOM, и CSSOM - это деревья. Они являются независимыми структурами данных. Браузер преобразует CSS файлы в карту стилей, которую он может понять и с которой может работать. Браузер считывает каждый набор правил в CSS, создает дерево узлов с родителями, детьми и соседями, основываясь на CSS селекторах.</p> + +<p>Как и в HTML, браузер должен преобразовать полученные правила CSS во что-то, с чем он может работать. Таким образом, весь этот процесс - это повторение формирования DOM, только для CSS.</p> + +<p>CSSOM дерево включает в себя стили пользовательского агента - это стили, которые браузер вставляет по умолчанию. Браузер начинает построение модели с наиболее общих правил для каждого узла, постепенно применяя более специфичные правила. Другими словами, он применяет правила каскадно. Отсюда и название CSS - Cascading Style Sheets.</p> + +<p>Построение CSSOM происходит очень быстро и не отображается отдельным цветом в средствах разработчика. Оно настолько быстрое, что чаще всего включается в показатель "Повторное вычисление стилей (Recalculate Styles)" в средствах разработчика. Этот показатель показывает общее время обработки стилей - обработку CSS, построение CSSOM и рекурсивное вычисление стилей. С точки зрения оптимизации производительности здесь нечего делать, так как построение CSSOM, в целом, занимает даже меньше времени, чем DNS запрос.</p> + +<h3 id="Остальные_процессы">Остальные процессы</h3> + +<h4 id="Компиляция_JavaScript">Компиляция JavaScript</h4> + +<p>Как CSS обработан и CSSOM создан, другие ресурсы, например, JavaScript-файлы, продолжают загружаться (спасибо сканеру предзагрузки). JavaScript по окончании загрузки должен быть интерпретирован, скомпилирован, обработан и исполнен. Скрипты преобразовываются в абстрактное синтаксическое дерево (AST). Некоторые браузеры берут {{glossary('Abstract Syntax Tree')}} и передают его в интерпретатор, который преобразует дерево в байт-код. Байткод исполняется в основном потоке. Весь этот процесс называется компиляцией.</p> + +<h4 id="Построение_дерева_доступности">Построение дерева доступности</h4> + +<p>Браузер также строит дерево <a href="/en-US/docs/Learn/Accessibility">доступности</a>, которое используется устройствами-помощниками для понимания и интерпретирования контента. Объектная модель доступности (accessibility object model, AOM) - это семантическая версия DOM. Браузер обновляет AOM в тот же момент, когда обновляется DOM. В то же время, дерево доступности не может быть изменено вспомогательными технологиями.</p> + +<p>Пока модель AOM не построена, содержимое страницы недоступно для <a href="/en-US/docs/Web/Accessibility/ARIA/ARIA_Screen_Reader_Implementors_Guide">голосовых помощников и считывателей экрана</a>.</p> + +<h2 id="Рендеринг">Рендеринг</h2> + +<p>Этапы рендеринга включают в себя стилизацию, компоновку (layout), отрисовку (paint) и, в некоторых случаях, композицию (composition). CSSOM и DOM деревья, созданные на предыдущем этапе комбинируются в дерево рендера, которое затем используется для расчёта положения каждого видимого элемента. После этого элементы будут отрисованы на экране. В некоторых случаях содержимое может быть вынесено на отдельные слои и совмещено (composition) - такой подход увеличивает производительность, позволяя отрисовывать содержимое экрана на графическом процессоре вместо ЦПУ. Это освобождает основной поток.</p> + +<h3 id="Стилизация">Стилизация</h3> + +<p>Третий шаг в критическом пути рендеринга - это комбинирование DOM и CSSOM в дерево рендеринга. Конструирование этого дерева начинается с прохода всего DOM-дерева от корня, с выявлением каждого видимого узла.</p> + +<p>Элементы, которые не должны быть показаны, например, <code><head></code>, а так же их дети или любые элементы с <code>display:none</code>, такие как <code>script { display: none; }</code>, не будут включены в дерево рендера, так как они не должны быть отрисованы. Узлы с правилом <code>visibility: hidden</code> включены в дерево рендера, так как они все равно занимают своё место. Так как мы не указали никаких специальных правил для перезаписи стилей агента по умолчанию, узел <code>script</code> в примере выше также не будет включен в дерево рендера.</p> + +<p>Каждый видимый узел имеет свои правила из CSSOM. Дерево рендера содержит все видимые узлы с их содержимым и вычисленными стилями. Стили определяются путем применения всех подходящих правил с использованием <a href="/en-US/docs/Web/CSS/Cascade">CSS каскада.</a></p> + +<h3 id="Компоновка_Layout">Компоновка (Layout)</h3> + +<p>Четвёртый шаг на критическом пути рендеринга - это запуск компоновки (layout) элементов дерева рендера. На этом шаге вычисляется геометрия каждого узла, то есть ширина, высота, положение элементов. Reflow (перекомпоновка) - это любой последующий процесс определения размеров и позиции для любой из частей целого документа.</p> + +<p>Как только дерево рендера построено - начинается layout. Дерево несёт в себе информацию о том, какие узлы должны быть отрисованы (даже если они невидимы), и какие стили должны быть применены, но в дереве нет никакой информации о размерах и позиции элементов. Чтобы определить эти значения, браузер начинает обход дерева.</p> + +<p>На веб-странице практически все элементы прямоугольны (box). Разные устройства и настройки подразумевают бесчисленное количество разных размеров видимой области. На начальной фазе браузер, учитывая размер видимой области, определяет какие размеры разных элементов должны быть на экране. Использует размер видимой области как базис, процесс начинает вычисление с элемента <code>body</code>, затем переходит к его потомкам, вычисляет размеры каждого элемента и резервирует место для тех элементов, размеры которых он ещё не знает (например, изображения).</p> + +<p>Момент, когда позиция и размеры узлов вычислены, называется layout. Последующие вычисления позиций и размеров называются reflow. В нашем примере предполагаемый начальный layout происходит перед тем, как изображение получено. Так как мы не задавали размер изображения, в момент получения изображения произойдет reflow.</p> + +<h3 id="Отрисовка_Paint">Отрисовка (Paint)</h3> + +<p>Последний шаг критического пути рендеринга - это отрисовка каждого отдельного узла на экране. Момент, когда это происходит впервые, называется <a href="/en-US/docs/Glossary/first_meaningful_paint">first meaningful paint</a> (первая значащая отрисовка). Во время фазы отрисовки или растеризации, браузер конвертирует каждый контейнер box в настоящие пиксели на экране (напомним, что данные контейнеров формируются на этапе layout). Отрисовка подразумевает рисование каждой визуальной частицы элемента на экране (текст, цвета, границы, тени) и рисование заменяемых элементов (картинки, кнопки). Браузер должен выполнять это быстро.</p> + +<p>Чтобы обеспечить плавную прокрутку и анимацию, отрисовка каждого элемента занимает весь основной поток. Сюда включается вычисление стилей, повторное вычисление стилей и отрисовка. Все эти этапы должны выполняться не дольше 16.67 мс. (1000мс. / 60 кадров в секунду). При разрешении 2048х1536 экран iPad содержит 3.145.000 пикселей, которые должны быть отрисованы. Это много! Для того, чтобы сделать инициирующую и повторную отрисовки быстрее, можно разбить весь процесс на несколько слоёв. Когда это случается - становится необходима композиция.</p> + +<p>Отрисовка может разбить элементы в дереве рендера на слои. Для того, чтобы ускорить их рендер, браузер может перенести отрисовку разных слоев на GPU (вместо основного потока CPU). Для переноса вычислений отрисовки на GPU вы можете использовать некоторые специальные HTML теги, например <code><a href="/en-US/docs/Web/HTML/Element/video"><video></a></code> и <code><a href="/en-US/docs/Web/HTML/Element/canvas"><canvas></a></code>; а также CSS-свойства <a href="/en-US/docs/Web/CSS/opacity"><code>opacity</code></a>, <code><a href="/en-US/docs/Web/CSS/transform">transform</a></code> и <code><a href="/en-US/docs/Web/CSS/will-change">will-change</a></code>. Узлы, созданные таким образом, будут отрисованы на их собственном слое, вместе с их потомками, если только потомки сами по себе не будут вынесены в отдельные слои.</p> + +<p>Слои улучшают производительность. Но, с точки зрения управления памяти, они неэффективны. Поэтому старайтесь не использовать их там, где в нет необходимости.</p> + +<h3 id="Композиция_Compositing">Композиция (Compositing)</h3> + +<p>Когда разделы документа отрисованы на разных слоях, а один слой находится над другим или перекрывает его, становится необходима композиция. Этот шаг позволяет браузеру гарантировать, что каждый слой отрисован на экране в правильном порядке, а содержимое отображается корректно.</p> + +<p>При догрузке ранее запрошенных ресурсов (например, изображений) может потребоваться перерассчитать размеры и положение элементов относительно друг друга. Этот перерасчёт - reflow - запускает перерисовку (repaint) и перекомпозицию (re-composite). Если мы заранее определили размер изображения, перерасчёт не будет необходим и в этом случае только тот слой, который должен быть перерисован - будет перерисован. Но если мы не определили размер изображения заранее, то браузер, после получения ответа от сервера, будет вынужден отмотать процесс рендеринга обратно к шагу компоновки (layout) и начать процесс отрисовки ещё раз.</p> + +<h2 id="Интерактивность">Интерактивность</h2> + +<p>Можно было бы подумать, что как только основной поток завершает отрисовку страницы - "всё готово". Это не всегда так. Если среди загружаемых ресурсов есть JavaScript, загрузка которого была корректно отложена, а запуск которого происходит только после события <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onload">onload</a></code>, основной поток начинает обработку скриптов. Во время этой обработки браузер не может обрабатывать события прокрутки, нажатий и др.</p> + +<p>{{glossary('Time to Interactive')}} (TTI, время до интерактивности) - это показатель того, как много времени проходит между самым первым сетевым запросом и моментом, когда страница становится интерактивной. В хронологии этот этап следует сразу за {{glossary('First Contentful Paint')}}. Интерактивностью называется показатель того, что страница отреагировала на действие пользователя за время в 50мс. Если процессор занят обработкой, компиляцией и выполнением JavaScript, то браузер не может отреагировать достаточно быстро, а значит страница считается не интерактивной.</p> + +<p>В нашем примере, даже несмотря на то, что изображение загрузилось быстро, скрипт <code>anotherscript.js</code>, размер которого достигает 2МБ, загружается долго. В этом случае пользователь увидит страницу очень быстро, но не будет способен взаимодействовать с ней, пока скрипт не будет загружен, обработан и исполнен. Это плохая практика. Старайтесь избегать полной загрузки процесса.</p> + +<p><img alt="The main thread is occupied by the downloading, parsing and execution of a javascript file - over a fast connection" src="https://mdn.mozillademos.org/files/16760/visa_network.png" style="height: 699px; width: 1200px;"></p> + +<p>В примере выше загрузка содержимого DOM заняла около 1.5 секунд. Все это время основной поток процесса был полностью загружен и не был способен обработать пользовательский ввод.</p> + +<h2 id="См._также">См. также:</h2> + +<ul> + <li><a href="/ru/docs/Web/Performance">Производительность Web</a></li> +</ul> diff --git a/files/ru/web/performance/how_long_is_too_long/index.html b/files/ru/web/performance/how_long_is_too_long/index.html new file mode 100644 index 0000000000..1812385647 --- /dev/null +++ b/files/ru/web/performance/how_long_is_too_long/index.html @@ -0,0 +1,34 @@ +--- +title: 'Тайминги производительности: как долго - долго?' +slug: Web/Performance/How_long_is_too_long +tags: + - Performance + - Web Performance + - Отзывчивость + - Производительность + - Тайминги +translation_of: Web/Performance/How_long_is_too_long +--- +<p>Не существует чётко установленного набора правил, который определяет медленную скорость загрузки страниц, но существуют особые руководства, которые рекомендуют определённые тайминги: загрузка контента - 1 секунда, ожидание - 50мс, анимация - 16,7мс, ответ на действия пользователя - от 50 до 200мс.</p> + +<h3 id="Загрузка_контента">Загрузка контента</h3> + +<p>Понятие "до секунды" часто считается оптимальным для загрузки. Но что это означает? Правило секунды должно рассматриваться как правило максимального времени, за которое пользователь поймет, что запрос был отправлен и будет загружен. Например, когда браузер принимает заголовок страницы или фоновый цвет и показывает её пользователю.</p> + +<p>Как правило, первый ресурс, который получает клиент - это HTML документ, который затем делает запрос на загрузку остальных ресурсов. Как было подмечено в <a href="/ru/docs/Web/Performance/Critical_rendering_path">статье о критическом пути рендеринга</a> - как только браузер получает данные, он сразу начинает их обработку, вместо того, чтобы дожидаться загрузки всех ресурсов.</p> + +<p>Да, одна секунда на загрузку - это хорошая цель. Но лишь немногие приложения достигают этой скорости. Всё зависит от ожиданий. Например, от приложения "Hello World", работающего в корпоративной (локальной) сети, будет ожидаться загрузка за милисекунды. Пользователь из северной Сибири, пользующийся Edge-мобильной сетью и устройством 5-летней давности, вероятно, посчитает даже 20-секундную загрузку быстрой. Однако, в среднем, если вы позволяете приложению не отвечать на запрос 3 или 4 секунды, вы, вероятно, потеряете пользователя. И, что ещё хуже, этот пользователь вряд ли вернётся к вам в ближайшее время.</p> + +<p>В деле оптимизации производительности рекомендуется обозначить амбициозные задачи по первичной загрузке контента. Например, 5 секунд для 3G сетей и 1.5 секунды для офисного Т1 канала. Для навигации внутри приложения цели должны быть ещё строже. К счастью, для оптимизации можно использовать Service Workers и кэширование.</p> + +<h3 id="Ожидание">Ожидание</h3> + +<p>Браузеры однопоточны (хотя существуют фоновые потоки, доступные с помощью web worker-ов). Это означает, что взаимодействие с пользователем, отрисовка и выполнение скриптов выполняются в одном потоке. Если поток занят вычислением сложной JavaScript логики, этот поток не сможет обрабатывать пользовательский ввод (например, нажатие кнопок). По этой причине важно разбивать выполнение скриптов на небольшие части, каждый из которых выполняется не больше 50мс. Это позволит потоку своевременно реагировать на пользовательский ввод.</p> + +<h3 id="Анимация">Анимация</h3> + +<p>Для того, чтобы прокрутка и другие анимации выглядели плавно, контент страницы должен обновляться с частотой 60 кадров в секунду (60 fps), то есть один кадр раз в 16.7мс. В эти 16.7мс. должны входить выполнение скриптов, компоновка и отрисовка. Делайте приложение таким, чтобы приложение могло использовать 6мс на отрисовку контента, а в остальные 10мс могло заниматься оставшимися вычислениями. Любая другая частота кадров, особенно если она отрывистая и непостоянная, создает впечатление зависающего приложения.</p> + +<h3 id="Отзывчивость">Отзывчивость</h3> + +<p>Когда пользователь взаимодействует с контентом - очень важно давать обратную связь пользователю. Время реакции не должно составлять больше 100мс, а лучше - 50мс. 50мс ощущаются пользователем как "мгновенно". Реакция на пользовательское взаимодействие должно чаще чувствоваться мгновенным (например, наведение курсора на кнопку). Но это не означает, что реакция должна быть одномоментной. В то время, как задержка в 100мс может вызвать чувство бессвязности действий пользователя и реакции системы, плавный переход между состояниями за время в 100-200мс позволит пользователю заметить, что взаимодействие началось и обрабатывается. Если ответ на действие пользователя занимает больше 100мс, предоставьте некоторую реакцию, которая скажет пользователю, что взаимодействие уже случилось и обрабатывается.</p> diff --git a/files/ru/web/performance/index.html b/files/ru/web/performance/index.html new file mode 100644 index 0000000000..51b68b881a --- /dev/null +++ b/files/ru/web/performance/index.html @@ -0,0 +1,291 @@ +--- +title: Web Performance +slug: Web/Performance +tags: + - API + - App + - App Performance + - HTML + - JavaScript + - Landing + - Mobile + - Mobile Performance + - NeedsTranslation + - Performance + - Performance Budget + - Start-Up Performance + - TopicStub + - Web + - Web Performance +translation_of: Web/Performance +--- +<p>Производительность в web - это объективные измерения и пользовательские ощущения, связанные с загрузкой и работой приложения. Производительность - это о том, как долго сайт грузится, становится интерактивным и отзывчивым, о том, как плавно происходит взаимодействие с контентом. Плавный ли скролл страницы? Все ли кнопки кликабельны? Всплывающие окна загружаются и показываются быстро? А анимируются? Хорошая производительность требует учета всех аспектов: как объективных, например, фактическое время загрузки страницы или частота смены кадров; так и субъективных - в буквальном смысле "как пользователь воспринимает систему".</p> + +<p>Чем дольше загружается ваше приложение, тем больше пользователей решаются избавиться от него. Очень важно уменьшать время загрузки приложения, а так же промежутка времени, за которое оно становится интерактивным. Но в то же время, важно добавлять в приложение новые возможности, которые уменьшают время отклика и делают приложение интерактивным за счет неочевидных хитростей, например, за счет асинхронной загрузки данных, которые не понадобятся пользователю "здесь и сейчас". </p> + +<p>Существуют инструменты измерения производительности, API и лучшие практики, которые помогут нам измерять и улучшать производительноть. Мы постараемся раскрыть их в следующей секции:</p> + +<h2 id="Ключевые_статьи_о_производительности">Ключевые статьи о производительности</h2> + +<p>{{LandingPageListSubpages}}</p> + +<div class="cleared topicpage-table"> +<div class="section"> +<h2 id="Beginners_tutorials">Beginner's tutorials</h2> + +<p>The MDN <a href="/en-US/docs/Learn/Performance">Web Performance Learning Area</a> contains modern, up-to-date tutorials covering Performance essentials. Start here if you are a newcomer to performance:</p> + +<dl> + <dt></dt> + <dt><a href="/en-US/docs/Learn/Performance/web_performance_overview">Web performance: brief overview</a></dt> + <dd>Overview of the web performance learning path. Start your journey here.</dd> + <dt><a href="/en-US/docs/Learn/Performance/What_is_web_performance">What is web performance?</a></dt> + <dd>This article starts the module off with a good look at what performance actually is — this includes the tools, metrics, APIs, networks, and groups of people we need to consider when thinking about performance, and how we can make performance part of our web development workflow.</dd> + <dt><a href="/en-US/docs/Learn/Performance/Perceived_performance">How do users perceive performance?</a></dt> + <dd> + <p>More important than how fast your website is in milliseconds, is how fast your users perceive your site to be. These perceptions are impacted by actual p<span>age load time, idling, responsiveness to user interaction, and the smoothness of scrolling and other animations. In this article, we discuss the various loading metrics, animation, and responsiveness metrics, along with best practices to improve user perception, if not the actual timings.</span></p> + </dd> + <dt><a href="/en-US/docs/Learn/Performance/Web_Performance_Basics">Web performance basics</a></dt> + <dd>In addition to the front end components of HTML, CSS, JavaScript, and media files, there are features that can make applications slower and features that can make applications subjectively and objectively faster. There are many APIs, developer tools, best practices, and bad practices relating to web performance. Here we'll introduce many of these features ad the basic level and provide links to deeper dives to improve performance for each topic.</dd> + <dt><a href="/en-US/docs/Learn/Performance/HTML">HTML performance features</a></dt> + <dd>Some attributes and the source order of your mark-up can impact the performance or your website. By minimizing the number of DOM nodes, making sure the best order and attributes are used for including content such as styles, scripts, media, and third-party scripts, you can drastically improve the user experience. This article looks in detail at how HTML can be used to ensure maximum performance.</dd> + <dt><a href="/en-US/docs/Learn/Performance/Multimedia">Multimedia: images and video</a></dt> + <dd>The lowest hanging fruit of web performance is often media optimization. Serving different media files based on each user agent's capability, size, and pixel density is possible. Additional tips like removing audio tracks from background videos can improve performance even further. In this article we discuss the impact video, audio, and image content has on performance, and the methods to ensure that impact is as minimal as possible.</dd> + <dt><a href="/en-US/docs/Learn/Performance/CSS">CSS performance features</a></dt> + <dd>CSS may be a less important optimization focus for improved performance, but there are some CSS features that impact performance more than others. In this article we look at some CSS properties that impact performance and suggested ways of handling styles to ensure performance is not negatively impacted.</dd> + <dt><a href="/en-US/docs/Learn/Performance/JavaScript">JavaScript performance best practices</a></dt> + <dd>JavaScript, when used properly, can allow for interactive and immersive web experiences — or it can significantly harm download time, render time, in-app performance, battery life, and user experience. This article outlines some JavaScript best practices that should be considered to ensure even complex content is as performant as possible.</dd> + <dt><a href="/en-US/docs/Learn/Performance/Mobile">Mobile performance</a></dt> + <dd>With web access on mobile devices being so popular, and all mobile platforms having fully-fledged web browsers, but possibly limited bandwidth, CPU and battery life, it is important to consider the performance of your web content on these platforms. This article looks at mobile-specific performance considerations.</dd> +</dl> + +<dl> +</dl> +</div> + +<div class="section"> +<h2 class="Other_documentation" id="Other_documentation" name="Other_documentation">Using Performance APIs</h2> + +<dl> + <dt><a href="/en-US/docs/Web/API/Performance_API/Using_the_Performance_API">Performance API</a></dt> + <dd>This guide describes how to use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance" title="The Performance interface provides access to performance-related information for the current page. It's part of the High Resolution Time API, but is enhanced by the Performance Timeline API, the Navigation Timing API, the User Timing API, and the Resource Timing API."><code>Performance</code></a> interfaces that are defined in the <a class="external external-icon" href="https://w3c.github.io/hr-time/" rel="noopener">High-Resolution Time</a> standard.</dd> + <dt><a href="/en-US/docs/Web/API/Resource_Timing_API/Using_the_Resource_Timing_API">Resource Timing API</a></dt> + <dd><a href="/en-US/docs/Web/API/Resource_Timing_API">Resource loading and timing</a> the loading of those resources, including managing the resource buffer and coping with CORS</dd> + <dt><a href="/en-US/docs/Web/API/Performance_Timeline/Using_Performance_Timeline">The performance timeline</a></dt> + <dd>The <a href="/en-US/docs/Web/API/Performance_Timeline">Performance Timeline</a> standard defines extensions to the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance" title="The Performance interface provides access to performance-related information for the current page. It's part of the High Resolution Time API, but is enhanced by the Performance Timeline API, the Navigation Timing API, the User Timing API, and the Resource Timing API."><code>Performance</code></a> interface to support client-side latency measurements within applications. Together, these interfaces can be used to help identify an application's performance bottlenecks.</dd> + <dt><a href="/en-US/docs/Web/API/User_Timing_API/Using_the_User_Timing_API">User Timing API</a></dt> + <dd>Create application specific timestamps using the <a href="/en-US/docs/Web/API/User_Timing_API">user timing API</a>'s "mark" and "measure" entry types - that are part of the browser's performance timeline.</dd> + <dt><a href="/en-US/docs/Web/API/Frame_Timing_API/Using_the_Frame_Timing_API">Frame Timing API</a></dt> + <dd>The <code><a href="/en-US/docs/Web/API/PerformanceFrameTiming">PerformanceFrameTiming</a></code> interface provides <em>frame</em> timing data about the browser's event loop.</dd> + <dt><a href="/en-US/docs/Web/API/Beacon_API/Using_the_Beacon_API">Beacon API</a></dt> + <dd><small>The <a href="/en-US/docs/Web/API/Beacon_API">Beacon</a> interface schedules an asynchronous and non-blocking request to a web server.</small></dd> + <dt><a href="/en-US/docs/Web/API/Intersection_Observer_API/Timing_element_visibility">Intersection Observer API</a></dt> + <dd>Learn to time element visibility with the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer API</a> and be asynchronously notified when elements of interest becomes visible.</dd> +</dl> + +<h2 class="Other_documentation" id="Other_documentation" name="Other_documentation">Other documentation</h2> + +<dl> + <dt><a href="/en-US/docs/Tools/Performance">Developer Tools Performance Features</a></dt> + <dd>This section provides information on how to use and understand the performance features in your developer tools, including <a href="/en-US/docs/Tools/Performance/Waterfall">Waterfall</a>, <a href="/en-US/docs/Tools/Performance/Call_Tree">Call Tree</a>, and <a href="/en-US/docs/Tools/Performance/Flame_Chart">Flame Charts</a>.</dd> + <dt><a href="/en-US/docs/Mozilla/Performance/Profiling_with_the_Built-in_Profiler">Profiling with the built-in profiler</a></dt> + <dd>Learn how to profile app performance with Firefox's built-in profiler.</dd> +</dl> +</div> +</div> + +<h2 id="Glossary_Terms">Glossary Terms</h2> + +<div class="index"> +<ul class="index"> + <li>{{glossary('Beacon')}}</li> + <li>{{glossary('Brotli compression')}}</li> + <li>{{glossary('Client hints')}}</li> + <li>{{glossary('Code splitting')}}</li> + <li>{{glossary('CSSOM')}}</li> + <li>{{glossary('Domain sharding')}}</li> + <li>{{glossary('Effective connection type')}}</li> + <li>{{glossary('First contentful paint')}}</li> + <li>{{glossary('First CPU idle')}}</li> + <li>{{glossary('First input delay')}}</li> + <li>{{glossary('First interactive')}}</li> + <li>{{glossary('First meaningful paint')}}</li> + <li>{{glossary('First paint')}}</li> + <li>{{glossary('HTTP')}}</li> + <li>{{glossary('HTTP_2', 'HTTP/2')}}</li> + <li>{{glossary('Jank')}}</li> + <li>{{glossary('Latency')}}</li> + <li>{{glossary('Lazy load')}}</li> + <li>{{glossary('Long task')}}</li> + <li>{{glossary('Lossless compression')}}</li> + <li>{{glossary('Lossy compression')}}</li> + <li>{{glossary('Main thread')}}</li> + <li>{{glossary('Minification')}}</li> + <li>{{glossary('Network throttling')}}</li> + <li>{{glossary('Packet')}}</li> + <li>{{glossary('Page load time')}}</li> + <li>{{glossary('Page prediction')}}</li> + <li>{{glossary('Parse')}}</li> + <li>{{glossary('Perceived performance')}}</li> + <li>{{glossary('Prefetch')}}</li> + <li>{{glossary('Prerender')}}</li> + <li>{{glossary('QUIC')}}</li> + <li>{{glossary('RAIL')}}</li> + <li>{{glossary('Real User Monitoring')}}</li> + <li>{{glossary('Resource Timing')}}</li> + <li>{{glossary('Round Trip Time (RTT)')}}</li> + <li>{{glossary('Server Timing')}}</li> + <li>{{glossary('Speculative parsing')}}</li> + <li>{{glossary('Speed index')}}</li> + <li>{{glossary('SSL')}}</li> + <li>{{glossary('Synthetic monitoring')}}</li> + <li>{{glossary('TCP handshake')}}</li> + <li>{{glossary('TCP slow start')}}</li> + <li>{{glossary('Time to first byte')}}</li> + <li>{{glossary('Time to interactive')}}</li> + <li>{{glossary('TLS')}}</li> + <li>{{glossary('TCP', 'Transmission Control Protocol (TCP)')}}</li> + <li>{{glossary('Tree shaking')}}</li> + <li>{{glossary('Web performance')}}</li> +</ul> +</div> + +<h2 id="Documents_yet_to_be_written">Documents yet to be written</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/Performance/JavaScript">JavaScript performance best practices</a></dt> + <dd>JavaScript, when used properly, can allow for interactive and immersive web experiences ... or it can significantly harm download time, render time, in app performance, battery life, and user experience. <span class="veryhardreadability"><span><span>This article outlines some JavaScript best practices that can ensure even complex content's performance is the highest possible.</span></span></span></dd> + <dt><a href="/en-US/docs/Learn/Performance/Mobile">Mobile performance</a></dt> + <dd>With web access on mobile devices being so popular, and all mobile platforms having fully-fledged web browsers, but possibly limited bandwidth, CPU, and battery life, it is important to consider the performance of your web content on these platforms. This article also looks at mobile-specific performance considerations.</dd> + <dt>Web font performance</dt> + <dd>An often overlooked aspect of performance landscape are web fonts. Web fonts are more prominent in web design than ever, yet many developers simply embed them from a third party service and think nothing of it. In this article, we'll covers methods for getting your font files as small as possible with efficient file formats and sub setting. From there, we'll go on to talk about how browsers text, and how you can use CSS and JavaScript features to ensure your fonts render quickly, and with minimal disruption to the user experience.</dd> + <dt>Performance bottlenecks</dt> + <dd></dd> + <dt>Understanding bandwidth</dt> + <dd> + <div> + <div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"><span><span>Bandwidth is the amount of data measured in Megabits(Mb) or Kilobits(Kb) that one can send per second. </span></span><span class="veryhardreadability"><span><span>This article explains the role of bandwidth in media-rich internet applications, how you can measure it, and how you can optimize applications to make the best use of available bandwidth</span></span></span><span><span>.</span></span></div> + </div> + </dd> + <dd></dd> + <dt>The role of TLS in performance</dt> + <dd> + <p>TLS—or HTTPS as we tend to call it—is crucial in creating secure and safe user experiences. While hardware has reduced the negative impacts TLS has had on server performance, it still represents a substantial slice of the time we spend waiting for browsers to connect to servers. This article explains the TLS handshake process, and offers some tips for reducing this time, such as OCSP stapling, HSTS preload headers, and the potential role of resource hints in masking TLS latency for third parties.</p> + </dd> + <dt>Reading performance charts</dt> + <dd>Developer tools provide information on performance, memory, and network requests. Knowing how to read <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Waterfall">waterfall</a> charts, <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Call_Tree">call trees</a>, traces, <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Flame_Chart">flame charts</a> , and <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Allocations">allocations</a> in your browser developer tools will help you understand waterfall and flame charts in other performance tools.</dd> + <dt>Alternative media formats</dt> + <dd>When it comes to images and videos, there are more formats than you're likely aware of. Some of these formats can take your highly optimized media-rich pages even further by offering additional reductions in file size. In this guide we'll discuss some alternative media formats, how to use them responsibly so that non-supporting browsers don't get left out in the cold, and some advanced guidance on transcoding your existing assets to them.</dd> + <dt>Analyzing JavaScript bundles</dt> + <dd>No doubt, JavaScript is a big part of modern web development. While you should always strive to reduce the amount of JavaScript you use in your applications, it can be difficult to know where to start. <span class="veryhardreadability"><span><span>In this guide, we'll show you how to analyze your application's script bundles, so you know </span></span><em><span>what</span></em><span><span> you're using, as well how to detect if your app contains duplicated scripts between bundles</span></span></span><span><span>.</span></span></dd> + <dt><a href="/ru/docs/Web/Performance/Lazy_loading">Lazy loading</a></dt> + <dd>Lazy loading (ленивая загрузка) - это стратегия, направленная на определение ресурсов как неблокирующих (не критических) для того, чтобы отложить загрузку этих ресурсов на тот момент, когда они действительно необходимы.</dd> + <dt>Lazy-loading JavaScript with dynamic imports</dt> + <dd>When developers hear the term "lazy loading", they immediately think of below-the-fold imagery that loads when it scrolls into the viewport. But did you know you can lazy load JavaScript as well? In this guide we'll talk about the dynamic import() statement, which is a feature in modern browsers that loads a JavaScript module on demand. Of course, since this feature isn't available everywhere, we'll also show you how you can configure your tooling to use this feature in a widely compatible fashion.</dd> + <dt><a href="/en-US/docs/Web/Performance/Controlling_resource_delivery_with_resource_hints">Controlling resource delivery with resource hints</a></dt> + <dd>Browsers often know better than we do when it comes to resource prioritization and delivery however they're far from clairyovant. Native browser features enable us to hint to the browser when it should connect to another server, or preload a resource before the browser knows it ever needs it. When used judiciously, this can make fast experience seem even faster. In this article, we cover native browser features like rel=preconnect, rel=dns-prefetch, rel=prefetch, and rel=preload, and how to use them to your advantage.</dd> + <dt><a href="/en-US/docs/Web/Performance/Performance_budgets">Performance Budgets</a></dt> + <dd>Marketing, design, and sales needs, and developer experience, often ad bloat, third-party scripts, and other features that can slow down web performance. To help set priorities, it is helpful to set a performance budget: a set of restrictions to not exceed during the development phase. In this article, we'll discuss creating and sticking to a performance budget. </dd> + <dt><a href="/en-US/docs/Web/Performance/Checklist">Web performance checklist</a></dt> + <dd>A performance checklist of features to consider when developing applications with links to tutorials on how to implement each feature, include service workers, diagnosing performance problems, font loading best practices, client hints, creating performant animations, etc.</dd> + <dt><a href="/en-US/docs/Web/Performance/Mobile_performance_checklist">Mobile performance checklist</a></dt> + <dd>A concise checklist of performance considerations impacting mobile network users on hand-held, battery operated devices.</dd> +</dl> + +<h2 id="See_also">See also</h2> + +<p>HTML</p> + +<ul> + <li><a href="/en-US/docs/Web/HTML/Element/picture">The <code><picture></code> Element</a></li> + <li><a href="/en-US/docs/Web/HTML/Element/video">The <code><video></code> Element</a></li> + <li><a href="/en-US/docs/Web/HTML/Element/source">The <code><source></code> Element</a></li> + <li><a href="/en-US/docs/Web/HTML/Element/img#Attributes">The <code><img> srcset</code> attribute</a> + <ul> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Web/HTML/Preloading_content">Preloading content with <code>rel="preload"</code></a> - <a href="https://w3c.github.io/preload/">(https://w3c.github.io/preload/ </a>)</li> +</ul> + +<p>CSS</p> + +<ul> + <li><a href="/en-US/docs/Web/CSS/will-change">will-change</a></li> + <li>GPU v CPU</li> + <li>Measuring layout</li> + <li>Font-loading best practices</li> +</ul> + +<p>JavaScript</p> + +<ul> + <li><a href="/en-US/docs/Web/Events/DOMContentLoaded">DOMContentLoaded</a></li> + <li><a href="/en-US/docs/Glossary/Garbage_collection">Garbage collection</a></li> + <li><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a></li> +</ul> + +<p>APIs</p> + +<ul> + <li><a href="/en-US/docs/Web/API/Performance_API">Performance API</a></li> + <li><a href="/en-US/docs/Web/API/Navigation_timing_API">Navigation Timing API</a></li> + <li><a href="/en-US/docs/Web/API/Media_Capabilities_API/Using_the_Media_Capabilities_API">Media Capabilities API</a></li> + <li><a href="/en-US/docs/Web/API/Network_Information_API">Network Information API</a></li> + <li><a href="/en-US/docs/Web/API/PerformanceNavigationTiming">PerformanceNavigationTiming</a></li> + <li><a href="/en-US/docs/Web/API/Battery_Status_API">Battery Status API</a></li> + <li><a href="/en-US/docs/Web/API/Navigator/deviceMemory">Navigator.deviceMemory</a></li> + <li><a href="/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer</a></li> + <li><a href="/en-US/docs/Web/API/User_Timing_API/Using_the_User_Timing_API">Using the User Timing AP</a>I</li> + <li><a href="/en-US/docs/Web/API/Long_Tasks_API">Long Tasks API</a></li> + <li><a href="/en-US/docs/Web/API/DOMHighResTimeStamp">High Resolution Timing API</a> (<a href="https://w3c.github.io/hr-time/">https://w3c.github.io/hr-time/)</a></li> + <li><a href="/en-US/docs/Web/API/Resource_Timing_API/Using_the_Resource_Timing_API">Resource Timing API</a></li> + <li><a href="/en-US/docs/Web/API/Page_Visibility_API">Page Visibility</a></li> + <li><a href="/en-US/docs/Web/API/Background_Tasks_API">Cooperative Scheduling of Background Tasks API</a> + <ul> + <li style="margin-top: 0.25em;"><a href="/en-US/docs/Web/API/Window/requestIdleCallback">requestIdleCallback() </a></li> + </ul> + </li> + <li><a href="/en-US/docs/Web/API/Beacon_API/Using_the_Beacon_API">Beacon API</a></li> + <li>Resource Hints - <a href="/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control">dns-prefetch</a>, preconnect, <a href="/en-US/docs/Web/HTTP/Link_prefetching_FAQ">prefetch</a>, and prerender</li> + <li><a href="/en-US/docs/Web/API/FetchEvent/navigationPreload">Fetchevent.navigationPreload</a></li> + <li><a href="/en-US/docs/Web/API/PerformanceServerTiming">Performance Server Timing API</a></li> +</ul> + +<p>Headers</p> + +<ul> + <li><a href="/en-US/docs/Web/HTTP/Headers/Content-Encoding">Content-encoding</a></li> + <li>HTTP/2</li> + <li><a href="/en-US/docs/Glossary/GZip_compression">gZip</a></li> + <li>Client Hints</li> +</ul> + +<p>Tools</p> + +<ul> + <li><a href="/en-US/docs/Tools/Performance">Performance in Firefox Developer Tools</a></li> + <li>Flame charts</li> + <li>The Network panel</li> + <li>Waterfall charts</li> +</ul> + +<p>Additional Metrics</p> + +<ul> + <li>Speed Index and Perceptual Speed Index</li> +</ul> + +<p>Best Practices</p> + +<ul> + <li><a href="/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">Using Service Workers</a></li> + <li><a href="/en-US/docs/Web/API/Web_Workers_API/Using_web_workers">Using Web Workers</a> + <ul> + <li><a href="/en-US/docs/Web/API/Web_Workers_API">Web Workers API</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Web/Apps/Progressive/Offline_Service_workers">PWA</a></li> + <li><a href="/en-US/docs/Web/HTTP/Caching">Caching</a></li> + <li>Content Delivery Networks (CDN)</li> +</ul> diff --git a/files/ru/web/performance/lazy_loading/index.html b/files/ru/web/performance/lazy_loading/index.html new file mode 100644 index 0000000000..27c6de4f4d --- /dev/null +++ b/files/ru/web/performance/lazy_loading/index.html @@ -0,0 +1,94 @@ +--- +title: Lazy loading +slug: Web/Performance/Lazy_loading +tags: + - Ленивая загрузка + - Производительность +translation_of: Web/Performance/Lazy_loading +--- +<p><span class="seoSummary"><strong>Lazy loading (ленивая загрузка) </strong><span>- это стратегия, направленная на определение ресурсов как неблокирующих (не критических) для того, чтобы отложить загрузку этих ресурсов на тот момент, когда они действительно необходимы. Так можно сократить длину <a href="/ru/docs/Web/Performance/Critical_rendering_path">критических этапов рендеринга</a>, что приводит к уменьшению времени загрузки приложения.</span></span></p> + +<p>Ленивая загрузка может происходить в разные моменты работы приложения, но, как правило, она запускается во время взаимодействия пользователя и системы, например, при скроллинге или навигации.</p> + +<h2 id="Обзор"><span>Обзор</span></h2> + +<p>Вместе с ростом web-приложений драматически вырос объем и размеры ресурсов, отправляемых клиентскому приложению. С 2011 по 2019 медианный рост размеров ресурсов вырос с <strong>~100KB</strong> до <strong>~400KB</strong> для настольных компьютеров и с <strong>~50KB</strong> до <strong>~350KB</strong> для мобильных. А размер изображений вырос вырос с <strong>~250KB</strong> до <strong>~900KB</strong> для настольных компьютеров и со <strong>~100KB</strong> до <strong>~850KB</strong> для мобильных.</p> + +<p>Очевидно, что такое повышение объёмов способствует увеличению длительности загрузки приложения. Один из способов её сократить - это отложить загрузку ресурсов, которые не являются критически важными для приложения. Например, вы посещаете приложение интернет-магазина, которое состоит из списка товаров и корзины. Очевидно, что вам не нужны изображения товаров, которые сейчас находится за пределами экрана; очевидно так же, что вам не нужно грузить все данные о содержимом корзины до тех пор, пока пользователь не перешёл к ней.</p> + +<h2 id="Стратегии">Стратегии</h2> + +<p>Ленивая загрузка (Lazy loading) может применяться к разным ресурсам и разными подходами. </p> + +<h3 id="Общий_подход"> Общий подход</h3> + +<p id="Code_splitting"><strong>Разделение кода (code splitting)</strong><br> + JavaScript, CSS и HTML могут быть разделены на небольшие части, называемые чанками (chunks). При первоначальной загрузке приложения вы можете отправлять не цельное приложение, а только необходимые части, например, только каркас разметки. Данные для заполнения этого каркаса могут быть подгружены позже, например, с помощью AJAX. Есть два вида разделения кода:</p> + +<ul> + <li>Разделение по точкам входа (entrypoint)</li> + <li>Динамическое (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">dynamic import()</a>)</li> +</ul> + +<h3 id="JavaScript"> JavaScript</h3> + +<p><strong>Указание типа "module</strong>"<br> + Любой тег скрипта с <code>type="module"</code> рассматривается как <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules">JavaScript module</a>, а его загрузка откладывается по умолчанию.</p> + +<h3 id="CSS"> CSS</h3> + +<p>По умолчанию, CSS рассматривается как блокирующий рендер (<a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path">render blocking</a>) ресурс, так что браузер не отобразит контент, пока объектная модель CSS (<a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model">CSSOM</a>) не будет завершена. Поэтому начальный CSS файл должен небольшим, чтобы быть доставленым так быстро, как это возможно. Рекомендуется использовать media-queries для того, чтобы вместо одного монолитного css-файла грузить специализированные</p> + +<pre><link href="style.css" rel="stylesheet" media="all"> +<link href="portrait.css" rel="stylesheet" media="orientation:portrait"> +<link href="print.css" rel="stylesheet" media="print"> +</pre> + +<p>Также в целях ускорения CSS можно применять оптимизации (<a href="CSS performance optimization">CSS optimizations</a>).</p> + +<h3 id="Шрифты"> Шрифты</h3> + +<p>По умолчанию, загрузка шрифтов откладывается на тот момент, пока дерево рендера (render tree) не сформировано полностью. Это приводит к тому, что текст страницы может появиться не сразу.</p> + +<p>Вы можете переопределить такое поведение и загрузить шрифты заранее, используя <code><link rel="preload"></code>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display">CSS font-display свойство</a> или <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Font_Loading_API">Font Loading API</a>.<br> + <br> + Смотри также: <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link">Element Link</a></p> + +<h3 id="Изображения"> Изображения</h3> + +<p>Очень часто веб-страницы содержат множество изображений, загрузка которых заметно нагружает канал передачи данных и увеличивает длительность загрузки. Подавляющая часть этих изображений находятся за видимой областью экрана и не являются необходимым (<a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path">non-critical</a>), а для взаимодействия с пользователем требуют действия (например, прокрутки до них).</p> + +<p><strong>Атрибут Loading </strong><br> + Атрибут {{htmlattrxref("loading", "img")}} элемента {{HTMLElement("img")}} (или {{htmlattrxref("loading", "iframe")}} атрибут для {{HTMLElement("iframe")}}) могут быть использованы, чтобы указать браузеру на необходимость отложить загрузку изображений / iframe до тех пор, пока пользователь не доскроллит до них.</p> + +<pre><img src="image.jpg" loading="lazy" alt="..." /> +<iframe src="video-player.html" loading="lazy"></iframe></pre> + +<p>Событие <code>load</code> запускается, когда все другие необходимые ресурсы были загружены. В это время, возможно (или даже наиболее вероятно), что изображения не будут загружены, даже если пользователь доскроллит до изображений и они будут в {{Glossary("visual viewport")}}.</p> + +<p>Вы можете определить, было ли загружено то или иное изображение, проверив Boolean значение {{domxref("HTMLImageElement.complete", "complete")}}.</p> + +<p><strong>Полифил</strong><br> + Для использованиях в браузерах, которые не поддерживают данную технологию, рекомендуется использовать полифилл: <a href="https://github.com/mfranzke/loading-attribute-polyfill" rel="noopener">loading-attribute-polyfill</a></p> + +<p><strong>Intersection Observer API</strong><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver">Intersection Observers</a> позволяют вам узнать, как наблюдаемый вами элемент входит или выходит из зоны видимости браузера (viewport).</p> + +<p><strong>Обработчики событий (Event handlers)</strong><br> + Intersection Observer API - относительно молодая технология, которая может не поддерживаться некоторыми устаревшими браузерами.<strong> </strong>Если поддержка браузеров важна для вас, есть несколько способов получить её:</p> + +<ul> + <li><a href="https://github.com/w3c/IntersectionObserver">polyfill intersection observer</a></li> + <li>вы можете вычислять, находится ли элемент во viewport каждый раз при срабатывании событий scroll, resize или orientation change.</li> +</ul> + +<h2 id="Смотри_также">Смотри также</h2> + +<ul> + <li><a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-blocking-css">Render blocking CSS</a></li> + <li><a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization#optimizing_loading_and_rendering">Optimizing loading and rendering</a></li> + <li><a href="https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video">Lazy loading images and video</a></li> +</ul> + +<dl> +</dl> diff --git a/files/ru/web/performance/navigation_and_resource_timings/index.html b/files/ru/web/performance/navigation_and_resource_timings/index.html new file mode 100644 index 0000000000..91cf4781b9 --- /dev/null +++ b/files/ru/web/performance/navigation_and_resource_timings/index.html @@ -0,0 +1,321 @@ +--- +title: Время загрузки страницы и ресурсов +slug: Web/Performance/Navigation_and_resource_timings +tags: + - Производительность +translation_of: Web/Performance/Navigation_and_resource_timings +--- +<p><span class="seoSummary"><strong>Тайминги навигации (Navigation timings) </strong>- это показатели, указывающие временные метки, в которые произошли события навигации. <strong>Тайминги ресурсов (Resource timings) </strong>- это детальные показатели по времени загрузки ресурсов. </span></p> + +<p>В этой статье мы рассмотрим как <a href="/en-US/docs/Web/API/PerformanceTiming">Performance Timing API</a>, так и Performance Entry API. И хотя первый API считается устаревшим, он все ещё поддерживается всеми браузерами, он прост и о нем полезно знать. В свою очередь, Performance Entry API является более продвинутым инструментом, который позволяет не только получить более сложные данные, но и позволяет разработчику измерять другие показатели, в дополнение к данным о навигации и загрузке ресурсов.</p> + +<h2 id="Performance_Timing_API"><strong>Performance Timing</strong> API</h2> + +<p><a href="/en-US/docs/Web/API/PerformanceTiming">PerformanceTiming API</a> - это JavaScript API для измерения времени загрузки страницы. Этот API считается устаревшим, но поддерживается во всех браузерах. На текущий момент рекомендуется использовать <a href="/en-US/docs/Web/API/PerformanceNavigationTiming">performanceNavigationTiming</a> API.</p> + +<p><a href="/en-US/docs/Web/API/PerformanceTiming">PerformanceTiming API </a>предоставляет собой read only данные в виде объекта, где значениями полей являются числа, указывающие на количество миллисекунд, которые прошли к моменту срабатывания того или иного события. Как показано на изображении ниже, процесс навигации можно разбить на следующие этапы: <code><a href="/en-US/docs/Web/API/PerformanceTiming/navigationStart">navigationStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/unloadEventStart">unloadEventStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/unloadEventEnd">unloadEventEnd</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/redirectStart">redirectStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/redirectEnd">redirectEnd</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/fetchStart">fetchStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/domainLookupStart">domainLookupStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/domainLookupEnd">domainLookupEnd</a></code>, <a href="/en-US/docs/Web/API/PerformanceTiming/connectStart">c<code>onnectStart</code></a> , <code><a href="/en-US/docs/Web/API/PerformanceTiming/connectEnd">connectEnd</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/secureConnectionStart">secureConnectionStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/requestStart">requestStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/responseStart">responseStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/responseEnd">responseEnd</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/domLoading">domLoading</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/domInteractive">domInteractive</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/domContentLoadedEventStart">domContentLoadedEventStart</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/domContentLoadedEventEnd">domContentLoadedEventEnd</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/domComplete">domComplete</a></code>, <code><a href="/en-US/docs/Web/API/PerformanceTiming/loadEventStart">loadEventStart</a></code>, и <code><a href="/en-US/docs/Web/API/PerformanceTiming/loadEventEnd">loadEventEnd</a></code>.</p> + +<p><img alt="Navigation Timing event metrics" src="https://mdn.mozillademos.org/files/16620/Screen_Shot_2019-05-03_at_1.06.27_PM.png"></p> + +<p>Благодаря этим метрикам и небольшим вычислениям мы можем определить важные показатели, например <a href="/en-US/docs/Glossary/time_to_first_byte">время до первого байта (time to first byte</a>), скорость загрузки страницы, поиска записи dns и даже узнать, является ли соединение безопасным.</p> + +<p>Чтобы получить доступ к этим данным, обратитесь к следующему объекту:</p> + +<pre>let time = window.performance.timing</pre> + +<p>Мы можем использовать эти данные, чтобы понять, как быстро работает приложение:</p> + +<p><img alt="entering window.performance.timing in the console lists all the timings in the PerformanceNavigationTiming interface" src="https://mdn.mozillademos.org/files/16824/navigatortiming.png"></p> + +<p>Описание показателей:</p> + +<table> + <thead> + <tr> + <th>Показатель</th> + <th>Пояснение</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{domxref("PerformanceTiming.navigationStart","navigationStart")}}</td> + <td> + <p>Момент, когда предыдущий документ в том же контексте (табе) запускает событие unload. Если предыдущего документа не было, значение этого показателя будет таким же, как и <code>PerformanceTiming.fetchStart</code>.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.secureConnectionStart","secureConnectionStart")}}</td> + <td> + <p>Началась установка (handshake) безопасного соединения. Если безопасного соединения нет, то значение равно <code>0</code>.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.redirectStart","redirectStart")}}</td> + <td>Начало первого HTTP редиректа. Если никаких редиректов не было, или один из редиректов перевёл документ на другой origin, то значение равно <code>0</code>.</td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.redirectEnd","redirectEnd")}}</td> + <td> + <p>Последний HTTP редирект завершён, то есть последний байт HTTP-ответа был получен. Если никаких редиректов не было, или один из редиректов перевёл документ на другой origin, то значение равно <code>0</code>.</p> + </td> + </tr> + <tr> + <td> + <p>{{domxref("PerformanceTiming.connectStart","connectStart")}}</p> + </td> + <td> + <p>Запрос на открытие соединения отправлен в сеть. Если транспортный уровень модели OSI сообщает об ошибке и установка соединения запускаются заново, то возвращается время старта последней попытки соединения. Если используется постоянное соединение, то значение показателя будет таким же, как и <code>PerformanceTiming.fetchStart</code>.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.connectEnd","connectEnd")}}</td> + <td> + <p>Момент, когда соединение открыто для передачи данных. Если транспортный уровень модели OSI сообщает об ошибке и установка соединения запускаются заново, то возвращается время завершения последней попытки соединения. Если используется постоянное соединение, то значение показателя будет таким же, как и <code>PerformanceTiming.fetchStart</code>. Соединение считается открытым, когда завершены все этапы установление безопасного соединения, например TLS Handshake или SOCKS Authentication.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.domainLookupEnd","domainLookupEnd")}}</td> + <td> + <p>Поиск домена завершён. Если используется постоянное соединение, или используются данные, сохраненные в локальном кэше, то значение показателя будет таким же, как и <code>PerformanceTiming.fetchStart</code>.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.domainLookupStart","domainLookupStart")}}</td> + <td>Начался поиск домена. Если используется постоянное соединение, или используются данные, сохраненные в локальном кэше, то значение показателя будет таким же, как и <code>PerformanceTiming.fetchStart</code>.</td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.fetchStart","fetchStart")}}</td> + <td> + <p>Браузер готов к загрузке документа с помощью HTTP-запроса. Этот этап всегда <strong>срабатывает до проверки</strong> кэша приложения.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.requestStart","requestStart")}}</td> + <td> + <p>Браузер посылает запрос на получение документа с сервера или из кэша. Если транспортный уровень сообщает об ошибке отправки запроса, а соединение переоткрывается - этот показатель будет перезаписан данными нового запроса.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.responseStart","responseStart")}}</td> + <td> + <p>Браузер получает первый байт ответа от сервера, кэша или локального ресурса.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.responseEnd","responseEnd")}}</td> + <td> + <p>Браузер получает последний байт ответа от сервера, кэша или локального ресурса. Если соединение закрывается раньше получения последнего байта - значение параметра указывает на момент закрытия соединения.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.domLoading","domLoading")}}</td> + <td> + <p>Парсер HTML начинает работу. В этот момент {{domxref('Document.readyState')}} изменяется на <code>'loading'</code> и срабатывает событие {{DOMxRef("Document.readystatechange_event", "readystatechange")}}.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.unloadEventStart","unloadEventStart")}}</td> + <td> + <p>Срабатывает событие {{DOMxRef("Window.unload_event", "unload")}}>, что говорит о времени, когда предыдущий документ начал выгружаться. Если предыдущего документа не было или переход к текущей странице подразумевал изменение origin (в т.ч. из-за редиректов), значение параметра равно <code>0</code>.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.unloadEventEnd","unloadEventEnd")}}</td> + <td> + <p>Обработчик события <code><a href="/en-US/docs/Web/Events/unload">unload</a></code> завершил свою работу. Если предыдущего документа не было или переход к текущей странице подразумевал изменение origin (в т.ч. из-за редиректов), значение параметра равно <code>0</code>.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.domInteractive","domInteractive")}}</td> + <td> + <p>HTML парсер завершил работу над основным документом. В этот момент <a href="/en-US/docs/Web/API/Document/readyState"><code>Document.readyState</code></a> изменяется на <code>'interactive'</code> и срабатывает событие <code><a href="/en-US/docs/Web/Events/readystatechange">readystatechange</a></code></p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.domContentLoadedEventStart","domContentLoadedEventStart")}}</td> + <td> + <p>Момент сразу перед тем, как парсер запускает событие <code><a href="/en-US/docs/Web/Events/DOMContentLoaded">DOMContentLoaded</a></code>. Это событие запускается после того, как все скрипты, которые должны исполниться сразу после парсинга, выполнены.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.domContentLoadedEventEnd","domContentLoadedEventEnd")}}</td> + <td> + <p>Момент сразу после исполнения всех скриптов, которые должны были исполниться.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.domComplete","domComplete")}}</td> + <td> + <p>Парсер HTML завершил работу над основным документом. В этот момент <a href="/en-US/docs/Web/API/Document/readyState"><code>Document.readyState</code></a> изменяется на <code>'complete'</code> и срабатывает событие <code><a href="/en-US/docs/Web/Events/readystatechange">readystatechange</a></code>.</p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.loadEventStart","loadEventStart")}}</td> + <td> + <p>Событие <code><a href="/en-US/docs/Web/Events/load">load</a></code> было отправлено текущему документу. Если это событие на момент измерения не было отправлено документу, значение параметра равно <code>0.</code></p> + </td> + </tr> + <tr> + <td>{{domxref("PerformanceTiming.loadEventEnd","loadEventEnd")}}</td> + <td> + <p>Обработка события <code><a href="/en-US/docs/Web/Events/load">load</a></code> завершена, то есть загрузка завершена. Если это событие ещё не произошло или не было послано документу, значение параметра равно <code>0</code>.</p> + </td> + </tr> + </tbody> +</table> + +<h3 id="Вычисление_таймингов">Вычисление таймингов</h3> + +<p>Мы можем использовать все эти значения, чтобы вычислить, сколько времени потребовалось на тот или иной этап:</p> + +<pre class="brush: js">let + dns = time.domainLookupEnd - time.domainLookupStart, + tcp = time.connectEnd - time.connectStart, + ssl != time.<code>secureConnectionStart</code>,</pre> + +<h3 id="Время_до_первого_байта">Время до первого байта</h3> + +<p><a href="/en-US/docs/Glossary/time_to_first_byte">Время до первого байта (Time to First Byte)</a> - это время между <code>navigationStart</code> и <code>responseStart</code> (момент, когда получен первый байт от сервера / кэша). Доступно в <code>performanceTiming</code> API</p> + +<pre class="brush: js">let ttfb = time.responseStart - time.navigationStart; +</pre> + +<h3 id="Время_загрузки_страницы">Время загрузки страницы</h3> + +<p><a href="/en-US/docs/Glossary/Page_load_time">Время загрузки страницы (Page load time)</a> - это время между <code>navigationStart</code> и моментом, когда событие <code>load</code> отправлено текущего документу. Доступно только в <code>performanceTiming</code> API</p> + +<pre class="brush: js">let pageloadtime = time.loadEventStart - time.navigationStart;</pre> + +<h3 id="Время_поиска_записи_DNS">Время поиска записи DNS</h3> + +<p>Время поиска записи DNS (DNS lookup) - это время между <code><a href="/en-US/docs/Web/API/PerformanceResourceTiming/domainLookupStart">domainLookupStart</a></code> и <code><a href="/en-US/docs/Web/API/PerformanceResourceTiming/domainLookupEnd">domainLookupEnd</a></code>. Оба эти параметра доступны как в <code>performanceTiming</code>, так и в <code>performanceNavigationTiming</code>.</p> + +<pre class="brush: js">let dns = time.domainLookupEnd - time.domainLookupStart;</pre> + +<h3 id="TCP">TCP</h3> + +<p>Время установки соединения <a href="/en-US/docs/Glossary/TCP">TCP</a> - это время между началом и окончанием попытки соединения:</p> + +<pre class="brush: js">tcp = time.connectEnd - time.connectStart;</pre> + +<h3 id="Установка_безопасного_подключения_SSL_negotiation">Установка безопасного подключения (SSL negotiation)</h3> + +<p><code><a href="/en-US/docs/Web/API/PerformanceResourceTiming/secureConnectionStart">secureConnectionStart</a></code> будет равен <code>undefined</code>, если SSL не доступен, <code>0</code> если <a href="/en-US/docs/Glossary/https">https</a> не используется или если временная метка доступна и используется. Другими словами, если безопасное соединение было использовано, то значение<code> secureConnectionStart</code> будет правдиво (<a href="/en-US/docs/Glossary/Truthy">truthy</a>), а время между<code> secureConnectionStart</code> и <code>requestStart</code> будет больше 0.</p> + +<pre class="brush: js">ssl = time.requestStart - time.<code>secureConnectionStart;</code></pre> + +<h2 id="Performance_Entry_API">Performance Entry API</h2> + +<p>Основные показатели производительности, рассмотренные выше, считаются устаревшими, но полностью поддерживаются современными браузерами. Взамен предлагается использовать {{domxref('PerformanceEntry', 'Performance Entry API')}}, который предоставляет инструмент для пометок и измерений времени одновременно с событиями navigation и загрузкой resource. Вы также можете создавать свои маркеры:</p> + +<pre class="brush: js">performance.getEntriesByType('navigation').forEach((navigation) => { + console.dir(navigation); +}); + +performance.getEntriesByType('resource').forEach((resource) => { + console.dir(resource); +}); + +performance.getEntriesByType('mark').forEach((mark) => { + console.dir(mark); +}); + +performance.getEntriesByType("measure").forEach((measure) => { + console.dir(measure); +}); + +performance.getEntriesByType('paint').forEach((paint) => { + console.dir(paint); +}); + +performance.getEntriesByType('frame').forEach((frame) => { + console.dir(frame); +});</pre> + +<p>В некоторых браузерах вы можете использовать<code> performance.getEntriesByType('paint')</code>, чтобы запросить измерения для <code>first-paint</code> и <code>first-contentful-paint</code>. Мы используем <code>performance.getEntriesByType('navigation')</code> и <code>performance.getEntriesByType('resource')</code> для запроса данных по навигации и загрузки ресурсов, соответственно.</p> + +<h2 id="Navigation">Navigation</h2> + +<p>Когда пользователь запрашивает веб-приложение,<a href="/en-US/docs/Learn/Performance/Populating_the_page:_how_browsers_work"> браузер должен получить некоторые мета-данные</a>, чтобы начать загрузку. Для этого пользовательский агент проходит серию шагов, такие как поиск записи DNS ({{glossary('DNS')}} lookup), TCP рукопожатие {{glossary('TCP handshake')}}, и установку безопасного соединения (SSL negotiation). Как только браузер установил соединение, происходит первый полезный запрос данных на сервера. Как только начинают поступать данные от сервера, браузер начинает парсить полученные данные, строит DOM, CSSOM, создает деревья рендера (render trees), чтобы в конце концов отрендерить страницу. В тот момент, когда браузер перестает парсить входящие данные, документ переходит в интерактивную стадию. Если в документе существуют отложенные к загрузке ресурсы (deferred scripts), которые должны быть обработаны, браузер парсит их. После этого запускается событие <a href="/en-US/docs/">DOMContentLoaded</a>, после которого готовность страницы завершена. Теперь документ может обрабатывать пост-загрузочные задачи. После этого документ маркируется, как полностью загруженный.</p> + +<pre>let navigationTimings = performance.getEntriesByType('navigation');</pre> + +<p>Метод <code>performance.getEntriesByType('navigation')</code> возвращает массив <a href="/en-US/docs/Web/API/PerformanceEntry">PerformanceEntry</a>, в котором содержатся объекты Navigation Timing.</p> + +<p><img alt="The results of when performance.getEntriesByType('navigation'); is entered into the console for this document" src="https://mdn.mozillademos.org/files/16825/perfgentrybytypenavigation.png" style="height: 628px; width: 897px;"></p> + +<p>Из этих данных можно многое извлечь. На изображении выше вы видите, что помимо самих таймингов, данные содержат имя документа и некоторую другую полезную информацию.</p> + +<pre>let timing = performance.getEntriesByType('navigation')[0];</pre> + +<h3 id="Протокол">Протокол</h3> + +<p>Мы можем проверить протокол, который используется дл получения ресурсов:</p> + +<pre>let protocol = <span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="cm-variable">timing</span>.<span class="cm-property">nextHopProtocol</span></span></span></span></pre> + +<p>В текущем случае в ответ будет <span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="cm-property"><code>h2</code> для <code>http/2</code>.</span></span></span></span></p> + +<h3 id="Сжатие">Сжатие</h3> + +<p>Чтобы узнать, как эффективно сжимаются данные при передаче, мы можем разделить <span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><code><span class="cm-property">transferSize</span></code><span class="cm-property"> на <code>decodedBodySize</code></span>, а затем вычесть результат из 100%. Для текущей страницы сжатие составляет до 74%.</span></span></span></p> + +<pre><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="cm-keyword">let</span> <span class="cm-def">compressionSavings</span> <span class="cm-operator">=</span> <span class="cm-number">1</span> <span class="cm-operator">-</span> (<span class="cm-variable">timing</span>.<span class="cm-property">transferSize</span> <span class="cm-operator">/</span> <span class="cm-variable">timing</span>.<span class="cm-property">decodedBodySize</span>)</span></span></span></pre> + +<p><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="cm-number">Мы могли бы использовать</span></span></span></span></p> + +<pre><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="cm-keyword">let</span> <span class="cm-def">compressionSavings</span> <span class="cm-operator">= </span><span class="cm-number">1</span> <span class="cm-operator">-</span> (<span class="cm-variable">timing</span>.<span class="cm-property">encodedBodySize</span> <span class="cm-operator">/</span> <span class="cm-variable">timing</span>.<span class="cm-property">decodedBodySize</span>)</span></span></span></pre> + +<p><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body">но <code>transfersize</code> так же включает в себя байты заголовков.</span></span></span></p> + +<p>Для сравнение, мы можем посмотреть на вкладку Network, где увидим, что было передано <span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body">22.04KB для файла, который в разархивированном виде занимает 87.24KB. </span></span></span></p> + +<p><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><img alt="View of the bytes transferred and the size via the network tab" src="https://mdn.mozillademos.org/files/16826/bytesdownloaded.png" style="height: 107px; width: 709px;"></span></span></span></p> + +<p><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body">Если мы проверим вычисления, то результат получится схожим: </span></span></span><code>1 - (22.04 / 87.24) = 0.747</code>. Тайминги навигации позволяют нам получить такие данные программно.</p> + +<p>Обратите внимание, что это данные для одного единственно документа, а не для всех ресурсов вместе взятых. В то же время, длительность загрузки, события-обработчики и тайминиги построения DOM / CSSOM влияют на продолжительность загрузки всего приложения, не только одного конкретного ресурса. Клиентские приложения, выполняющиеся в браузере, могут выглядеть быстрее, если данные объемом 300КБ вы передаете сжатыми до 100КБ, но это все не значит, что JavaScript, CSS или другие медиа-ресурсы не раздувают приложение и не делают его медленее. Проверка уровня сжатия - это очень важно, но не менее важно проверять длительность парсинга ресурсов и время между тем, как завершен DOMContentLoaded и DOM готов к работе. Может случиться так, что время парсинга скриптов и обработка скриптами результатов в основном потоке (main thread) приведет к зависанию интерфейса.</p> + +<h3 id="Время_запроса">Время запроса</h3> + +<p>API не предоставляет все измерения, которые разработчик хочет получить. Например, как долго продлилось выполнение запроса? Отдельного поля в объекте данных нет. Однако, мы можем использовать измерения, чтобы вычислить то, что нам нужно.</p> + +<p>Чтобы определить время ответа, вычтите время старта запроса из времени старта получения ответа. Запрос стартует ровно в тот момент, когда клиент запрашивает ресурс с сервера (или из кэша). Ответ начинается ровно в тот момент, когда клиент получает первый байт.</p> + +<pre class="brush: js">request = <a href="/en-US/docs/Web/API/PerformanceNavigationTiming/responseStart"><code>timing.responseStart</code></a> - <a href="/en-US/docs/Web/API/PerformanceNavigationTiming/requestStart"><code>timing.requestStart</code></a></pre> + +<h3 id="Длительность_события_загрузки">Длительность события загрузки</h3> + +<pre class="brush: js">load = <a href="/en-US/docs/Web/API/PerformanceNavigationTiming/loadEventEnd"><code>timing.loadEventEnd</code> - <code>timing.loadEventStart</code></a> </pre> + +<h3 id="DOMContentLoaded_event">DOMContentLoaded event</h3> + +<p>Длительность события DOMContentLoaded определяется разностью моментов, когда клиент запускает событие DOMContentLoaded и когда это событие завершено. Старайтесь держать эту величину меньше 50ms - тогда ваш интерфейс будет отзывчивым.</p> + +<pre class="brush: js">DOMContentLoaded = <a href="/en-US/docs/Web/API/PerformanceNavigationTiming/domContentLoadedEventEnd"><code>timing.domContentLoadedEventEnd</code></a> - <a href="/en-US/docs/Web/API/PerformanceNavigationTiming/domContentLoadedEventStart"><code>timing.domContentLoadedEventStart</code></a></pre> + +<h3 id="Длительность_Duration">Длительность (Duration)</h3> + +<p>В объекте данных есть поле Длительность (<code>Duration</code>). Длительность - это разница между <a href="/en-US/docs/Web/API/PerformanceNavigationTiming/loadEventEnd">PerformanceNavigationTiming.loadEventEnd</a> и <a href="/en-US/docs/Web/API/PerformanceEntry/startTime">PerformanceEntry.startTime</a> properties.</p> + +<p>Интерфейс PerformanceNavigationTiming, кроме того, дает информацию о том, какой тип навигации вы измеряете, возвращая <code>navigate</code>, <code>reload</code>, <code>back_forward</code> или <code>prerender</code>.</p> + +<h2 id="Resource">Resource</h2> + +<p>В то время, как тайминги навигации измеряют произодительность загрузки и парсинга основного файла HTML, этот файл служит лишь точкой входа для загрузки других ресурсов. Поэтому нам так же важно знать, как быстро загружаются дополнительные ресурсы. Для измерения этих данных нужно использовать Resource Timing. Большая часть измерений в этом объекте похожи: здесь и поиск домена в DNS, и TCP установка соединения и т.д.</p> + +<p><img alt="Graphic of Resource Timing timestamps" src="https://mdn.mozillademos.org/files/12093/ResourceTiming-TimeStamps.jpg"></p> + +<p>Для того, чтобы получить эти данные, выполните команду:</p> + +<pre class="syntaxbox"><code><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="cm-variable">performance</span>.<span class="cm-property">getEntriesByType</span>(<span class="cm-string">"resource"</span>)</span></span></span></code></pre> + +<h2 id="См._также">См. также</h2> + +<ul> + <li>{{domxref("PerformanceNavigationTiming")}}</li> + <li>{{domxref("PerformanceResourceTiming")}},</li> + <li>{{domxref("PerformanceMark")}}</li> + <li>{{domxref("PerformanceMeasure")}}</li> + <li>{{domxref("PerformancePaintTiming")}}</li> +</ul> diff --git a/files/ru/web/performance/optimizing_startup_performance/index.html b/files/ru/web/performance/optimizing_startup_performance/index.html new file mode 100644 index 0000000000..941c5894a9 --- /dev/null +++ b/files/ru/web/performance/optimizing_startup_performance/index.html @@ -0,0 +1,85 @@ +--- +title: Оптимизация запуска +slug: Web/Performance/Optimizing_startup_performance +translation_of: Web/Performance/Optimizing_startup_performance +--- +<div class="summary"> +<p>Часто упускаемый из вида аспект разработки приложений - это скорость запуска приложения. Даже если вы прикладываете много усилий к оптимизации работы приложений, именно этот этап может быть пропущен. Как долго запускается ваше приложение? Создается ли впечатление, что устройство зависает, пока приложение запускается? Все эти симптомы заставляют пользователя считать, что приложение сломано или что-то идет не так. Всегда будет не лишним убедиться, что ваше приложение запускается плавно. В этой статье мы поделимся некоторыми подсказками, которые помогут вам оптимизировать запуск приложения, вне зависимости от того, пишете ли вы его с нуля или работаете над уже существующим.</p> +</div> + +<h2 id="Приятный_запуск">Приятный запуск</h2> + +<p>Не имеет значения, какую платформу вы используете, всегда будет правильным обеспечить как можно более быструю загрузку приложения. Так как это наиболее общая проблема, мы не будем заострять на ней внимание здесь. Однако, мы обратим внимание на наибольшую проблему Web-приложений: синхронная загрузка ресурсов. Решением этой проблемы был бы максимальный переход на асинхронную загрузку ресурсов. Это означает, что инициализриующий код не должен запускаться в одно единственном обработчике событий в главном потоке процесса.</p> + +<p>Вместо этого, вы можете разбить ваш код так, чтобы часть его обрабатывалась в <a href="/en-US/docs/DOM/Using_web_workers" title="/en-US/docs/DOM/Using_web_workers">Web worker</a>, что выделит его в отдельные фоновые неблокирующие треды (например, запросы данных и их обработка). Затем, все, что должно быть выполнено в основном потоке (например, пользовательские события или рендеринг интерфейса) должно быть разбито на небольшие кусочки так, чтобы обработчик браузера выполнял небольшие куски кода итеративно, а не за один подход. Это позволит ваше приложению выглядеть отзывчивым даже во время первоначальной загрузки.</p> + +<p>Почему так важно делать все это асинхронно? Помимо причин, перечисленных выше, подумайте о влиянии, которые оказывают зависшие приложения: пользователь не может отменить запуск, даже если он запустил приложение по ошибке. Если приложение запускается в браузере, пользователь даже не сможет закрыть вкладку. В конечно счете это может привести даже к системным предупреждениям о "медленных скриптах" или "исчерпании памяти". А ведь было время, когда каждая вкладка не работала в отдельном процессе, как сейчас, а потому повисшая вкладка приводила к зависанию всего браузера! Вы должны не просто делать загрузку приложения "мягкой", но и давать пользователю знать о процессе загрузки: показывайте ему прогресс-бары или этапы, которые проходит приложение. Это позволит пользователю убедиться, что приложение не зависло.</p> + +<h3 id="Было_бы_желание...">Было бы желание...</h3> + +<p>Если вы начинаете ваш проект с нуля, обычно очень легко начать писать код "правильно", делая все изначально асинхронным. Все вычисления при запуски должны выполняться в фоновых потоках, в то время как основной поток должен держаться максимально очищенным от лишних функций. Включайте индикатор прогресса для того, чтобы пользователь знал, что сейчас происходит и не думал, что приложение сломано. В теории, если вы только начинаете разработку приложения - это все должно быть очень просто.</p> + +<p>С другой стороны, потребуются некоторые ухищрения, если вы пытаетесь портировать существующее десктопное приложение в Web или привыкли писать такие. Десктопные приложения обычно не нуждаются в написании кода в асинхронной манере, потому что операционная система берет заботу об этом на себя. В исходниках такого приложения может быть лишь один поток обработки кода, но даже он может быть легко разбит на асинхронные этапы (запуском каждой новой итерации потока по отдельности). В таких приложениях запуск часто представляет собой последовательную монолитную процедуру, которая время от времени обращается к метрикам прогресса и обновляет их.</p> + +<p>И хотя вы можете использовать <a href="/en-US/docs/DOM/Using_web_workers" title="/en-US/docs/DOM/Using_web_workers">Web workers</a>, чтобы обработать очень большие и "тяжелые" скрипты асинхронно, вы должны учитывать некоторые ограничения. Web Worker-ы не имеют доступа к некоторым API браузера: DOM, <a href="/en-US/docs/WebGL" title="/en-US/docs/WebGL">WebGL</a> или audio, они не могут посылать синхронные сообщения в основной поток, вы даже не можете проксировать некоторые из этих API в основной поток. Это всё означает, что вы можете поместить в Web Worker-ы только "чистые функции", но вам все равно придется вычислять огромную часть данных в основном потоке. Поэтому очень полезно разрабатывать систему так, чтобы в ней было как можно больше чистых функций - так их будет проще делегировать последствии.</p> + +<p>Тем не менее, даже код в основном потоке можно сделать асинхронным, приложив лишь небольшие усилия.</p> + +<h2 id="Переход_к_асинхронности">Переход к асинхронности</h2> + +<p>Есть несколько предложений, как сделать процесс загрузки асинхронным:</p> + +<ul> + <li>Используйте атрибуты {{ htmlattrxref("defer") }} или {{ htmlattrxref("async") }} на тегах script. Это позволит HTML парсерам продолжать парсинг документа, вместо того, чтобы переключаться на скачивание / парсинг / выполнение скриптов.</li> + <li>Если вам нужно декодировать какой-то ресурс (например, JPEG для превращения его в текстуру в WebGL), делайте это в Worker-ах.</li> + <li>Когда вы имеете дело с данными, поддерживаемыми браузером, используйте встроенные декодеры, а не пишите свои. Это касается, например, декодинга изображений / видео. Производители браузеров стараются применять лучшие техники, наиболее совместимые с их кодовой базой. Кроме того, многие браузеры поддерживают параллельное выполнение таких обработчиков.</li> + <li>Любая обработка данных, которая может быть сделана параллельно <strong>должна </strong>быть сделана параллельно.</li> + <li>Не подключайте скрипты и стили, которые не критичны для запуска приложения, в инициализирующий HTML. Загружайте их только тогда, когда это необходимо.</li> + <li>Сокращайте размеры ваших JavaScript-файлов. Попробуйте отправлять минифицированный код и используйте сжатие, например Gzip или Brotli.</li> + <li>Используйте дополнительные атрибуты (например preconnect или preload) всегда, когда есть возможность сказать браузеру, что является критическим для вашей системы.</li> +</ul> + +<p>Чем больше вещей вы можете сделать асинхронно, тем большие преимущества многоядерных процессоров вы сможете задействовать.</p> + +<h3 id="Проблемы_портирования">Проблемы портирования</h3> + +<p>Когда первоначальная загрузка завершена и начинается обработка приложения в основном потоке, вполне возможно, что ваше приложение обязано быть однопоточным, особенно если это портированная версия. Очень важно попытаться помочь процессу запуска приложения, порефакторив код, сделав его композитным, состоящим из маленьких кусочков, каждый из которых может быть обработан последовательно основным потоком. В этом случае, в промежутке между выполнением этих кусочков кода браузер сможет выделить время на обработку ввода (например, клик) или на обработку микро-задач.</p> + +<p>В случае, если вы портируете ваше приложение, вы наверняка знаете о <a href="/en-US/docs/Mozilla/Projects/Emscripten">Emscripten. </a>Это решение предоставляет API, которое поможет с подобным рефакторингом. Например, вы можете использовать <code>emscripten_push_main_loop_blocker()</code>, чтобы определить фнукцию, как выполняемую после того, как основной поток разрешит продолжить работу. Создавая такие функции, создавая очередь, которая должна выполниться в определенном порядке, вы можете с легкостью разгрузить основной поток.</p> + +<p>Конечно, все это не отменяет необходимости рефакторинга кода так, чтобы он работал лучше и это займет время. Но для старта этого может оказаться достаточно.</p> + +<h3 id="Насколько_далеко_я_должен_зайти">Насколько далеко я должен зайти?</h3> + +<p>Стоит держать в голове, что браузер начинает беспокоиться о вашем скрипте в том случае, если он блокирует основной поток больше, чем на 10 секунд. В идеале, вы не должны блокировать работу страницы так долго. И пока вы держите показатели загрузки приложения ниже этих значение - все должно быть ок. Но не забывайте, что если кто-то имеет не такой мощный компьютер или мобильное устройство, как у вас, то код, выполняющийся у вас за 2 секунды, у этого пользователя может занять 10 секунд. Для этого полезно использовать CPU Throttling, который предоставляется средствами разработчиков в некоорых браузерах.</p> + +<h2 id="Другие_предложения">Другие предложения</h2> + +<p>Существуют другие вещи, которые могут влиять на скорость запуска приложения, и одна лишь асинхонность не спасёт от всего. Вот несколько из них:</p> + +<dl> + <dt>Время загрузки</dt> + <dd>Держите в голове, как много времени занимает загрузка данных вашего приложения. Если приложение действительно большое, популярное и должно обновлять данные часто, вы должны использовать как можно более быстрый хостинг (или даже несколько хостингов для разных регионов). Так же не забывайте сжимать данные.</dd> + <dt>Влияние GPU</dt> + <dd>Компиляция шейдеров или загрузка текстур в GPU может занять время, особенно для по-настоящему сложных WebGL приложений. Давайте пользователю знать о том, что загрузка или обработка данных продолжается фоном, чтобы он знал, когда лучше переходить в загруженные части приложения.</dd> + <dt>Размер данных</dt> + <dd>Делайте всё, чтобы избежать лишних данных. Чем меньше лишних данных запрашивается каждый раз, тем работает приложение. Используйте нормализацию данных и кеширование.</dd> + <dt>Субъективные факторы</dt> + <dd>Любая вещь, которую вы предлагаете пользователю во время запуска приложения и с которой он может взаимодействовать, заставляет время течь быстрее. Это забавно, но прогресс-бар, который показывается 3 секунды ощущается более быстрым, чем пустая страница в течение 1 секунды. Добавляйте подсказки к вашему приложению, рассказывайте интересные факты или просто показывайте что-то красивое - это уже улучшит восприятие.</dd> +</dl> + +<h2 id="См._также">См. также</h2> + +<ul> + <li><a href="/en-US/docs/Apps" title="/en-US/docs/Apps">Apps</a></li> + <li><a href="/en-US/docs/Games" title="/en-US/docs/Games">Games</a></li> +</ul> + +<div class="originaldocinfo"> +<h2 id="Original_Document_Information" name="Original_Document_Information">Информация об оригинальном документе:</h2> + +<ul> + <li>Автор: Alon Zakai</li> + <li>Исходник: <a href="http://mozakai.blogspot.com/2012/07/bananabread-or-any-compiled-codebase.html" title="http://mozakai.blogspot.com/2012/07/bananabread-or-any-compiled-codebase.html">BananaBread (or any compiled codebase) Startup Experience</a></li> +</ul> +</div> diff --git a/files/ru/web/performance/performance_budgets/index.html b/files/ru/web/performance/performance_budgets/index.html new file mode 100644 index 0000000000..ca3615982f --- /dev/null +++ b/files/ru/web/performance/performance_budgets/index.html @@ -0,0 +1,74 @@ +--- +title: Бюджет производительности +slug: Web/Performance/Performance_budgets +translation_of: Web/Performance/Performance_budgets +--- +<p><span class="seoSummary">Бюджет производительности - это лимит для предотвращения регрессий. Этот бюджет может быть применен к файлам, типам файлов, всем ресурсам приложения, определенным общим показателям (например, <a href="/en-US/docs/Glossary/Time_to_interactive">Время до интерактивности</a>) пользовательским показателям (например, Время до главного элемента) или к пороговым значениям к определенным точкам во времени. </span></p> + +<h2 id="Зачем_нужен_бюджет">Зачем нужен бюджет?</h2> + +<p>Бюджет существует для отражения желаемых вами целей. С бюджетом вы сможете осознанно выстраивать компромиссы между пользовательским опытом и объективным индикаторами эффективности приложения (например, конверсией)</p> + +<p>Эти цели можно разбить на категории:</p> + +<ul> + <li>Временные (например, <a href="/en-US/docs/Glossary/Time_to_interactive">Время до интерактивности,</a> <a href="/en-US/docs/Glossary/First_contentful_paint">Первая отрисовка контента</a>).</li> + <li>Количественный (например, размер загруженных JS файлов, количество изображений).</li> + <li>Определенные правилами (например. индекс <a href="https://developers.google.com/speed/pagespeed/insights/">Pagespeed</a>, баллы Lighthouse).</li> +</ul> + +<p>Главная цель такого подхода - сокращение регрессии. Но этот подход может помочь предсказать поведение приложения в будущем. Например, в Сентябре 50% месячного бюджета было использовано за неделю - значит, нужно ждать увеличения потребления контента, нагрузки на сервера и т.д.</p> + +<p>Кроме того, подход может раскрыть некоторые нужды разработчиков (например, может оказаться, что в финальном коде вашего приложения половину объема занимает огромная библиотека, из которой вы используете только мизерную часть функционала).</p> + +<h2 id="Как_определить_бюджет">Как определить бюджет?</h2> + +<p>Бюджет должен включать 2 уровня:</p> + +<ul dir="ltr"> + <li>Предупреждение</li> + <li>Ошибка</li> +</ul> + +<p>Уровень предупреждения позволяет вам быть проактивным и заниматься техническим долгом, не блокируя разработку нового функционала</p> + +<p>Уровень ошибки - это граница, по достижении которой приложение воспринимается негативно.</p> + +<p>Для начала, вам нужно выяснить, какими технологиями пользуются ваши пользователи. Например, большая часть пользователей приходят с Anroid-телефонов бюджетного уровня и подсоединяются через 3G). Для подобного исследования существует множество <a href="/en-US/docs/Learn/Performance/Web_Performance_Basics">инструментов</a>. Эти метрики должны стать базой для бюджета размера файлов.</p> + +<p>Базовая цель - достигнуть показателя <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">"Время до интерактивности" до 5 секунд при 3G/4G, и до 2 секунд для последующих загрузок</a>. Однако, вы можете придумать свои цели, основанные на контенте приложения, географии пользователей и технологиях.</p> + +<p>Например, для приложения с большим количеством текста (блоги, новостные сайты), показатель <a href="/en-US/docs/Glossary/First_contentful_paint">Первая отрисовка контента (First Contentful Paint)</a> будет гораздо лучше показывать, с чем сталкивается пользователь. Иными словами, этот показатель покажет, как быстро пользователь начинает читать. И этот показатель должен быть включен в специфичные бюджеты, например, бюджет шрифтов, где вы можете применять разные техники для оптимизации. Например, <a href="/en-US/docs/Web/CSS/@font-face/font-display">font-display</a>, чтобы улучшить <a href="/en-US/docs/Learn/Performance/perceived_performance">Субъективно Ощущаемую производительность</a>).</p> + +<p>Но самая главная цель таких бюджетов - это возможность корелляции Производительности и Бизнес-целей. Когда вы определяете какие-то показатели, вы должны сфокусироваться на пользовательском опыте. Только он может диктовать, как мы должны изменять приложение таким образом, чтобы не просто улучшить конверсию, но и предсказать вероятность того, что пользователь вернётся.</p> + +<h2 id="Как_создать_бюджет">Как создать бюджет?</h2> + +<p>Во время разработки вы можете использовать несколько инстурментов, чтобы проверять некоторые показатели:</p> + +<ul> + <li>Сборщики (наприме, <a href="https://webpack.js.org/">webpack</a>), из коробки содержат<a href="https://webpack.js.org/configuration/performance/"> инструменты оценки производительности</a>, которые сообщат вам, если какой-то из файлов превысил допустимые размеры.</li> + <li><a href="https://github.com/siddharthkp/bundlesize">Bundlesize</a>, позволяет вам определить и проверять размеры файлов каждый раз при интеграции вашего кода с помощью <a href="/en-US/docs/Mozilla/Continuous_integration">CI</a>.</li> +</ul> + +<p>Проверка размеров файлов - это лишь первый рубеж защиты от регрессий. Преобразование этих показателей во временные может быть сложным, потому что во время разработки окружение разработчика может не включать в себя сторонние библиотеки или оптимизации, которые обычно присутствют в Production сборках.</p> + +<p>Поэтому, рекомендуется определить базовые линии для каждой метрики бюджета с учетом разницы между окружением разработчика и боевым окружением.</p> + +<p>С этим может помочь, например, <a href="https://github.com/GoogleChromeLabs/lighthousebot">Lighthouse Bot</a>, который можно встроить в <a href="https://travis-ci.org/">Travis CI</a> и использовать для получения аналитики <a href="https://developers.google.com/web/tools/lighthouse/">Lighthouse</a> и <a href="https://webpagetest.org">Webpage Test</a>. Этот бот будет сообщать об ошибке или успешном прохождении тестов на основе определённых минимальных оценок.</p> + +<h2 id="Как_я_могу_усилить_влияние_бюджета">Как я могу усилить влияние бюджета?</h2> + +<p>Чем раньше вы сможете определить новую трату к бюджету, тем лучше вы сможете оценить текущее состояние приложения и указать на необходимые оптимизации.</p> + +<p>Кроме того, лучше иметь несколько бюджетов и быть проактивным. Бюджеты должны отражать ваши текущие цели, но не должны мешать экспериментам. Например, вы можете привнести функционал, который увеличит общее время загрузки приложения, но попытается увеличить пользовательскую вовлечённость (например, как долго пользователь остается на странице).</p> + +<p>Бюджет помогает вам сохранить оптимальное поведение ваших текущих пользователей, когда вы пытаетесь выйти на новые рынки или привнести что-то новое в ваше приложение.</p> + +<h2 id="См._также">См. также</h2> + +<ul> + <li><a href="https://addyosmani.com/blog/performance-budgets/">Start Performance Budgeting</a> by Addy Osmani</li> + <li><a href="https://web.dev/fast/performance-budgets-101">Performance Budgets 101</a> by Milica Mihajlija</li> + <li><a href="https://timkadlec.com/remembers/2019-03-07-performance-budgets-that-stick/">Performance Budgets That Stick</a> by Tim Kadlec</li> +</ul> diff --git a/files/ru/web/performance/rum-vs-synthetic/index.html b/files/ru/web/performance/rum-vs-synthetic/index.html new file mode 100644 index 0000000000..a2d0a17bec --- /dev/null +++ b/files/ru/web/performance/rum-vs-synthetic/index.html @@ -0,0 +1,39 @@ +--- +title: 'Мониторинг производительности: реальные пользователи и их эмуляция' +slug: Web/Performance/Rum-vs-Synthetic +tags: + - RUM + - Производительность + - Регрессия + - Синтетические тесты +translation_of: Web/Performance/Rum-vs-Synthetic +--- +<p><strong>Синтетический мониторинг</strong> и <strong>мониторинг реальных пользователей (Real User Monitoring, RUM) </strong>- два способа мониторинга и получения данных о веб-производительности. Эти два подхода дают два разных обзора производительности и каждый имеет свои преимущества, области применения и минусы. RUM, в основном, лучше подходит для понимания долгосрочных трендов, в то время как синтетический мониторинг хорошо подходит для тестирования регрессий, их быстрого обнаружения и быстрой реакции на них в процессе разработки. В этой статье мы определим и сравним оба подхода.</p> + +<h2 id="Синтетический_мониторинг"><strong>Синтетический мониторинг</strong></h2> + +<p>Синтетический мониторинг включает в себя мониторинг производительности в "лабораторных" условиях, обычно с помощью автоматизированных инструментов в цельном окружении. Такой подход включает в себя создание скриптов, симулирующих путь, который может пройти пользователь, пользуясь приложением. Таким образом тестируются не настоящие пользователи, но заранее определенный набор инструкций, который выполняется в предопределенном окружении.</p> + +<p>Пример такого мониторинга - <a href="https://WebPageTest.org">WebPageTest.org</a>. Ресурс предоставляет контролируемое окружение, где вы определяете географию, сеть, устройства, браузеры и кешированные данные. Сервис предоставляет Waterfall график для каждого ресурса, который используется в вашем приложении и грузится сторонними библиотеками (например, рекламными или аналитическими инструментами).</p> + +<p>Контролируя переменные окружения, вы можете понять, где в производительности узкие места и каковы их источники. Однако, все эти данные не отражают реальный пользовательский опыт, особенно если поведение пользователя не ограничивается только лишь просмотром страницы.</p> + +<p>Синтетический мониторинг может быть важным компонентом тестирования регрессий и средством мониторинга выпущенного и работающего приложения. Ухудшение базовых метрик производительности в ходе CI/CD-процесса должно вести к приостановке релиза, по крайней мере до тех пор, пока не выяснится, почему метрики ухудшились. Если проблема возникает только в Production-режиме, синтетические тесты предоставят информацию, которая поможет идентифицировать, изолировать и решить проблему, прежде чем она отразится на пользователях.</p> + +<h2 id="Мониторинг_реальных_пользователей_RUM">Мониторинг реальных пользователей (RUM)</h2> + +<p id="Real_User_Monitoring_(RUM)"><strong>Мониторинг реальных пользователей (Real User Monitoring, RUM) </strong>измеряет производительность приложения на устройствах конечных пользователей. В основе подхода - сторонний скрипт, который вставляет другие скрипты на каждую страницу. Эти дополнительные скрипты измеряют производительность и предоставляют отчеты о ней. Этот подход помогает не только узнать, насколько производительно приложение, но и дает информацию об использовании приложения, например, о географии, распределении пользователей или влиянии такого распределения на пользовательский опыт.</p> + +<p>В отличие от синтетического мониторинга, RUM собирает данные от настоящих пользователей, вне зависимости от их устройств, браузеров, сети или геолокации. Пока пользователь взаимодействует с приложением, тайминги такого взаимодействия записываются, вне зависимости от того, какое действие выполняется в конкретный момент. Такой мониторинг собирает данные о реальном использовании приложения, а не о том поведении, которое ожидают разработчики или, скажем, отдел маркетинга. Это особенно важно для больших веб-сайтов или сложных приложений, где функционал или содержимое постоянно меняются, а количество пользователей может очень сильно расти, создавая новые нагрузки и требования.</p> + +<p>Используя RUM, бизнес может лучше понять своих клиентов и определить зоны сайта, которые требуют большего внимания. Более того, RUM может помочь понять географию или канал распространения приложения. Знание своих пользователей и трендов поможет вам выстроить бизнес-планы и думать наперёд, позволяя вам определить приоритетные зоны, которые требует оптимизации и улучшения производительности.</p> + +<h2 id="Сравнение_подходов">Сравнение подходов</h2> + +<p>Синтетический мониторинг хорошо подходит для отлавливания регрессий в ходе разработки приложения. Особенно полезным может оказаться занижение скорости сети ({{glossary('network throttling')}}). Такой подход довольно прост, недорог и великолепно подходит для тестирования определённых точек приложения по мере того, как вы вносите изменения в код. Но он даёт лишь узкий обзор производительности и не говорит о том, что испытывает пользователь.</p> + +<p>Тестирование на реальных пользователях, в свою очередь, дает информацию о настоящих пользователях, которые используют приложение или веб-сайт. И хотя получение и обработка таких данных обходится дороже и не так проста, такой подход дает жизненно важные данные о пользовательском опыте.</p> + +<h2 id="API_для_измерения_производительности">API для измерения производительности</h2> + +<p>Существует множество сервисов мониторинга. Если вы хотите создать свой сервис, взгляните на следующие API: не только {{domxref("PerformanceNavigationTiming")}} и {{domxref("PerformanceResourceTiming")}}, но также {{domxref("PerformanceMark")}}, {{domxref("PerformanceMeasure")}}, и {{domxref("PerformancePaintTiming")}}.</p> diff --git a/files/ru/web/performance/understanding_latency/index.html b/files/ru/web/performance/understanding_latency/index.html new file mode 100644 index 0000000000..1e36dd3bf1 --- /dev/null +++ b/files/ru/web/performance/understanding_latency/index.html @@ -0,0 +1,122 @@ +--- +title: Время ожидания (latency) +slug: Web/Performance/Understanding_latency +tags: + - Connection + - Network + - Web Performance + - latency + - Время ожидания + - Производительность + - Соединение + - сеть +translation_of: Web/Performance/Understanding_latency +--- +<p><strong>Latency</strong> (дальше - <strong>время ожидания</strong>) - это время, которое требуется на доставку пакета данных от источника к пункту назначения. В деле оптимизации производительности важно сокращать проблемы, которые приводят к длительному времени ожидания. Также необходимо научиться тестировать работу приложения в условиях плохого соединения. В этой статье мы рассмотрим само понятие времени ожидание, его причины, способы детекции и исправления.</p> + +<h2 id="Что_такое_время_ожидания">Что такое "время ожидания"?</h2> + +<p>Время ожидания - это промежуток времени, который проходит с момента старта запроса до момента получения ответа. При запросе первых 14КБ время ожидания дольше, потому что весь запрос включает в себя {{glossary('DNS')}} запрос, соединение {{glossary('TCP handshake')}}, установление безопасного соединения {{glossary('TLS')}}. Последующие запросы будут иметь меньшее время ожидания, так как соединение с сервером уже установлено.</p> + +<p>Время ожидания описывает величину задержки сети или, в частности, интернет-соединения. Малое время ожидания подразумевает едва заметные задержки. Большое время ожидания подразумевает большие задержки. Одно из основных усилий в оптимизации приложения должно быть направлено на снижение этого времени ожидания.</p> + +<p>Улучшить время ожидания, связанное только с одним ресурсом, например, с HTML кодом страницы - это довольно просто. Но приложения, как правило, состоят из множества запросов: CSS, JavaScript-файлы, медиа. Чем больше запросов исходит со страницы, тем большее влияние оказывает время ожидания на общие впечатления пользователя.</p> + +<p>При соединении с малым временем ожидания ресурсы появляются практически мгновенно. При соединении с большим временем ожидания задержка между запросом и ответом становится заметной. Мы можем определить время ожидания, измеряя скорость, с которой данные проходят из одной сети к другой.</p> + +<p>Время ожидания может быть измерено для одного направления (например, сколько времени проходит до отправки запроса) или для полного пути обмена сообщениями (сколько времени заняли запрос и получение ответов).</p> + +<h2 id="Эмуляция_времени_ожидания">Эмуляция времени ожидания</h2> + +<p>Для эмуляции большой времени задержки вы можете использовать средства разработчика. В англоязычных интерфейсах эмуляция называется "Throttling".</p> + +<p><img alt="Emulate latency by emulating throttling" src="https://mdn.mozillademos.org/files/16805/emulate_latency.png" style="height: 268px; width: 829px;"></p> + +<p>В Firefox кнопка переключения находится на панели Network (Сеть), в заголовке таблицы. С помощью инструмента вы можете испытать работу приложения в сетях от GPRS до высокоскоростных. Также вы можете сами указать скорость загрузки и время ожидания. Браузеры предоставляют разные наборы значений, но, как правило, все они покрывают перечисленные ниже случаи:</p> + +<table> + <thead> + <tr> + <th>Selection</th> + <th>Download speed</th> + <th>Upload speed</th> + <th>Minimum latency (ms)</th> + </tr> + </thead> + <tbody> + <tr> + <td>GPRS</td> + <td>50 Kbps</td> + <td>20 Kbps</td> + <td>500</td> + </tr> + <tr> + <td>Regular 2G</td> + <td>250 Kbps</td> + <td>50 Kbps</td> + <td>300</td> + </tr> + <tr> + <td>Good 2G</td> + <td>450 Kbps</td> + <td>150 Kbps</td> + <td>150</td> + </tr> + <tr> + <td>Regular 3G</td> + <td>750 Kbps</td> + <td>250 Kbps</td> + <td>100</td> + </tr> + <tr> + <td>Good 3G</td> + <td>1.5 Mbps</td> + <td>750 Kbps</td> + <td>40</td> + </tr> + <tr> + <td>Regular 4G/LTE</td> + <td>4 Mbps</td> + <td>3 Mbps</td> + <td>20</td> + </tr> + <tr> + <td>DSL</td> + <td>2 Mbps</td> + <td>1 Mbps</td> + <td>5</td> + </tr> + <tr> + <td>Wi-Fi</td> + <td>30 Mbps</td> + <td>15 Mbps</td> + <td>2</td> + </tr> + </tbody> +</table> + +<h2 id="Временные_показатели_сети">Временные показатели сети</h2> + +<p>Кроме того, во вкладке Network (Сеть), вы можете изучить, как много времени занял тот или иной запрос. На изображении ниже - пример загрузка SVG файла размером 267.5КБ.</p> + +<div><img alt="The time it took for a large SVG asset to load." src="https://mdn.mozillademos.org/files/16807/latencymlw.png" style="height: 342px; width: 1311px;"></div> + +<p>Когда запрос находится в очереди, ожидая установки соединения с сервером, он считается заблокированным. Блокировка случается, когда браузер уже обрабатывает слишком много соединений одновременно (в большей степени это относится к предыдущему поколению HTTP1.1, который позволял поддерживать до 6 соединений за раз). Пока все соединения обрабатываются, браузер не может загружать другие ресурсы. Как только загрузка ресурса завершается - соединение освобождается.</p> + +<p><strong>DNS поиск (DNS resolution) </strong>- это время, которое требуется на {{glossary('DNS lookup')}}. Это процесс, когда браузер находит соответствие между именем домена и его IP-адресом. Если вы обращаетесь ко многим доменам, DNS поиск занимает больше времени.</p> + +<p><strong>Установка соединения (Connecting) </strong>- это время, требуемое на {{glossary('TCP handshake')}}. Это процесс SYN - ACK, когда браузер и сервер договариваются о формате соединения. Как и DNS, чем больше соединений к разным серверам вы используете, тем больше время создания соединений.</p> + +<p> <strong>{{glossary('TLS')}} handshake</strong> - это процесс установки безопасного соединения. И хотя установка безопасного соединения занимает дополнительное время, ни в коем случае не стоит отказываться от него, жертвуя безопасностью пользователей.</p> + +<p><strong>Отправка</strong> <strong>(Sending)</strong> - время, необходимое для отправки HTTP запроса на сервер.</p> + +<p><strong>Ожидание (Waiting</strong>) - это ожидание обработки запроса сервером. Например, вы хотите получить изображение. В этом случае сервер должен обратиться к файловой системе, найти файл, передать его HTTP соединению. В случае сложных динамических запросов процесс может занимать секунды и минуты. Это ещё одно место для оптимизации, но уже не клиентское, а серверное.</p> + +<p><strong>Получение (Receiving</strong>) - это время на загрузку ответа. Этот показатель - комбинация скорости сети и размера файла. Если изображение было закешировано, то его загрузка может произойти мгновенно. Но если не использовать кэш и включить эмуляцию медленной сети, изображение может загружаться 43 секунды!</p> + +<h2 id="Измерение_времени_ожидания">Измерение времени ожидания</h2> + +<p><strong>Время ожидания сети (Network latency</strong>) - это время, которое требуется на отправку запроса и полную загрузку ответа.</p> + +<p><strong>Время ожидания диска (Disk latency</strong>) - это время, которое требуется устройству на то, чтобы получить запрос, понять его, найти файл в файловой системе и вернуть ответ.</p> diff --git a/files/ru/web/performance/основы/index.html b/files/ru/web/performance/основы/index.html new file mode 100644 index 0000000000..fd97d25650 --- /dev/null +++ b/files/ru/web/performance/основы/index.html @@ -0,0 +1,224 @@ +--- +title: Основы производительности +slug: Web/Performance/Основы +tags: + - Apps + - Firefox + - Gecko + - Guide + - Performance + - Производительность +translation_of: Web/Performance/Fundamentals +--- +<div class="summary"> +<p><span class="seoSummary">Английское слово Performance, которое используется в статьях о производительности приложений, также можно перевести, как "эффективность". Этот документ объясняет основы производительности, того как браузеры помогают улучшить её и какие инструменты и процессы вы можете использовать, чтобы её улучшить. </span></p> +</div> + +<h2 id="Что_такое_производительность">Что такое производительность?</h2> + +<p>Ощущаемая пользователем "производительность" - это единственная производительность, которая имеет значение. Пользователи взаимодействуют с системой с помощью ввода каких-то данных: прикосновений, движения и речи. В ответ, они получают реакцию, основанную на зрительном, тактильном или слуховом аппаратах. Производительность - это качество того, как система реагирует на действия пользователя.</p> + +<p>При прочих равных, код, оптимизированный для каких-то иных целей, кроме ощущаемой пользователем производительности (здесь и дальше UPP, user-perceived performance) всегда проигрывает коду, который оптимизирован для UPP. Упрощенно говоря, пользователи предпочитают отзывчивое и плавное приложение, которое обрабатывает 1,000 транзакций к базе данных в секунду грубому неотзывчивому приложению, которое обрабатывает 100,000,000 запросов в секунду. Конечно, это не означает, что другие метрики становятся ненужным, но первой вашей целью должна быть UPP.</p> + +<p>Следующие разделы укажут и объяснят некоторые метрики производительности:</p> + +<h3 id="Отзывчивость">Отзывчивость</h3> + +<p>Отзывчивость - это то, как быстро система предлагает ответ (или множество ответов) на запрос пользователя. Например, когда пользователь нажимает на экран, он ожидает, что пиксели под пальцем изменятся каким-то образом. Для этого случая взаимодействия хорошей метрикой будет время, которое прошло между моментом нажатия и изменением пикселей.</p> + +<p>Отзывчивость иногда включает в себя несколько этапов. Запуск приложения - один из важнейших этапов. Мы обсудим его ниже.</p> + +<p>Отзывчивость важна просто потому, что пользователи теряются и злятся, когда их игнорируют. Ваше приложение игнорирует пользователя каждую секунду, когда оно не отвечает на пользовательский ввод.</p> + +<h3 id="Частота_кадров">Частота кадров</h3> + +<p>Частота кадров - это частота, с которой система перерисовывает пиксели, отображаемые пользователю. Это знакомая концепция: каждый предпочитает, скажем, игры, которые работают в режиме 60 кадров в секунду играм, которые работают с частотой 10 кадров в секунду. Даже если они не смогут объяснить причины этого.</p> + +<p>Частота кадров важна примерно так же, как "качество обслуживания". Дисплеи устройств спроектированы так, чтобы обманывать глаза пользователей, доставляя фотоны света так, чтобы изображение было похожим на реальное. Например, бумага, покрытая напечатанными буквами, отражает фотоны определённым образом. Манипулируя рендерингом, приложения-читалки пытаются отправить фотоны похожим образом, обманывая глаза.</p> + +<p>Ваш мозг знает, что движение - это не отрывчатый или дискретный процесс, а плавный и последовательный. Дисплей устройств с высокой частотой кадров сделаны просто для того, чтобы сделать эту иллюзию более реальной. (Интересно, что стробоскопы переворачивают эту концепцию, заставляя наш мозг создавать иллюзию дискретной реальности).</p> + +<div class="note"> +<p><strong>Заметка</strong>: люди обычно не могут почувствовать разницу между частотами кадров выше 60Hz. По этой причин большая часть современных электронных дисплеев спроектированы для обновления картинки с такой частотой. Однако, для некоторых живых существ такая частота кадров будет казаться замедленной. Например, для колибри.</p> +</div> + +<h3 id="Использование_памяти">Использование памяти</h3> + +<p>Использование памяти - это отдельная ключевая метрика. В отличии от отзывчивости и частоты кадров, пользователи не могут напрямую почувствовать использование памяти, но её использование влияет на "состояние пользователя". Идеальная система будет поддерживать 100% состояния всех приложений всё время: все приложения будут запускаться одновременно, а каждое приложение будет возвращаться к состоянию, которое было в последний раз, когда пользователь с ним взаимодействовал (состояние приложения хранится в компьютерной памяти - поэтому это сравнение его с user state довольно точное).</p> + +<p>Отсюда следует одно неочевидное заключение: <u>хорошо спроектированная система не заботится об увеличении свободной памяти.</u> <strong>Память - это ресурс,</strong> а свободная память - неиспользуемый ресурс. Наоборот, хорошо спроектированная система использует достаточно много памяти, чтобы обеспечить такое состояние, когда пользователь не чувствует изменений в производительности.</p> + +<p>Это не означает, что система должна тратить память. Когда система использует больше памяти, чем это необходимо для поддержания состояния приложения - она тратит память. В этом случае, другое приложение (или даже другое состояние), которые могли бы использовать эту память - не могут её использовать. На практике, ни одна система не может поддерживать в памяти все состояния одновременно. Разумное распределение памяти, достаточное для поддержки состояния приложения - это важная проблема, которую мы рассмотрим позже.</p> + +<h3 id="Использование_энергии">Использование энергии</h3> + +<p>Последний показатель, который нужно упомянуть - это потребление энергии. Подобно использованию памяти, пользователь чувствует потребление памяти опосредованно, отмечая время, через которое устройство начинает изменять воспринимаемую пользователем производительность (UPP). Для минимизации отрицательных эффектов использования энергии, мы должны делать систему экономной.</p> + +<p>Для примера, вспомните, как работают мобильные устройства: вы можете включить режим энергосбережения, когда отключаются другие системы. Но есть и более жесткий режим, который включается автоматически, когда заряд уменьшается до 5% - система включает троттлинг процессора, замедляя выполнение всех инструкций.</p> + +<p>Всю оставшуюся часть статьи мы будем обсуждать производительность в свете этих показателей.</p> + +<h2 id="Оптимизация_платформы">Оптимизация платформы</h2> + +<p>В этой секции приводится краткий обзор того, как Firefox/Gecko вкладывается в производительность в целом, не заостряя внимание на конкретных приложениях. Для разработчиков и пользователей это будет вопрос на ответ "Как платформа помогает мне?".</p> + +<h3 id="Web_технологии">Web технологии</h3> + +<p>Web платформа предоставляет много инструментов, некоторые из которых лучше подходят для конкретных задач, а некоторые - хуже. Логика приложений пишется на JavaScript. Для отображения графики разработчики могут использовать HTML или CSS (т.е. используются высокоуровневные декларативные языки); разработчики также могут использовать низкоуровневые интерфейсы, доступные в {{ htmlelement("canvas") }} (включая <a href="/en-US/docs/Web/WebGL">WebGL</a>). Где-то между HTML/CSS и Canvas лежит <a href="/en-US/docs/Web/SVG">SVG</a>, который предлагает некоторые преимущества обеих систем.</p> + +<p>HTML и CSS значительно увеличивают производительность, иногда снижая частоту кадров и не давая контролировать каждый пиксель при рендере. Текст и изображения перерисовываются автоматически, UI-элементы автоматически получают системную тему, а система предоставляет некоторую "встроенную" поддержку для некоторых случаев, о которых разработчик может и не задумываться изначально. Например, отображение контента при разных разрешениях.</p> + +<p>Элемент Холст (<code>canvas</code>) предоставляет прямой доступ к пиксельному буферу, где разработчик может рисовать.Это даёт разработчику возможность контролировать каждый пиксель во время рендеринга, точно контролировать частоту кадров; но тогда разработчик должен иметь в виду работу с большим количеством разрешений экранов и ориентаций; RTL языками и т.д. Разработчики, работающие напрямую с холстами, используют либо знакомое 2D API, либо API WebGL, достаточно "близкий к железу" и по большей части придерживающийся OpenGL ES 2.0.</p> + +<div class="note"> +<p><strong>Заметка: </strong>Firefox OS оптимизирована для работы с приложениями, основанными на Web технологиях: <a href="/en-US/docs/Web/HTML">HTML</a>, <a href="/en-US/docs/Web/CSS">CSS</a>, <a href="/en-US/docs/Web/JavaScript">JavaScript</a> и т.д. За исключением некоторых базовых служб операционной системы, весь код Firefox OS пришел из Web приложений и движка Gecko. Даже оконный менеджер операционной системы написан на HTML, CSS и JavaScript. В связи с тем, что ядро операционной системы написано на этих технологиях, было критически важно соблюсти производительность этих технологий. В Firefox OS не может быть какого-то "запасного выхода". И это очень полезно для разработчиков, потому что теперь сторонние приложения могут использовать все преимущества оптимизации операционной системы. Не существует какого-то "магического зелья производительности", доступного только для предустановленных приложений.</p> + +<p>См. <a href="/en-US/docs/Archive/B2G_OS/Firefox_OS_apps/Performance/Firefox_OS_performance_testing">Тестирование производительности Firefox OS</a> для подробностей.</p> +</div> + +<h3 id="Как_рендерит_Gecko">Как рендерит Gecko</h3> + +<p>Движок Gecko JavaScript поддерживает just-in-time (JIT) компиляцию. Благодаря этому, логика приложения выполняется примерно так же, как это происходит в других приложениях на виртуальных машинах - например, Java Virtual Machines - а в некоторых случаях эффективность этих приложений близка к "нативному коду".</p> + +<p>Инструменты, необходимые для работы с HTML, CSS и Canvas оптимизированы несколькими путями. Например, композиция (этап, известный как Layout) в HTML/CSS и код, отвечающий за графику в Gecko, сделаны таким образом, чтобы уменьшить количество операций ревалидации и перерисовки для общих случаев (например, скроллинг); эти оптимизации включены "по умолчанию", поэтому разработчики пользуются ими бесплатно. Буферы пикселей, отрисованных как для Gecko "автоматически", так и для <code>canvas</code> "вручную", минимизируют количество копий, которые передаются в буфер кадров дисплея. Чтобы достичь этого, Gecko старается избегать создания промежуточных слоев (например, во многих других операционных системах создаются пиксельные фоновые буферы для каждого отдельного приложения), но взамен Gecko использует специальные участки памяти ддя хранения графических буферов. К этой памяти имеет прямой доступ железо, которое ответственно за формирование картинки. Сложные сцены рендерятся с использованием графического адаптера (видеокарты). А простые сцены, для экономии энергии, рендерятся специальным выделенным железом для композиции, в то время, как графический адаптер находится в режиме ожидания или выключен.</p> + +<p>Для продвинутых приложений полностью статичный контент скорее является исключением, чем правилом. Такие приложения используют динамический контент, анимируемый с помощью {{ cssxref("animation") }} и {{ cssxref ("transition") }}. Переходы и анимации особенно важны для приложений: разработчики могут использовать CSS для объявления сложного поведения с помощью простого высокоуровнего синтаксиса. С другой стороны, движок Gecko хорошо оптимизирован для того, чтобы рендерить такую анимацию эффективно. В целом, общепринятые анимации передаются к обработке системному компоновщику, который может отрендерить их в эффективном, энергосберегающем режиме. </p> + +<p>Производительность запуска приложения так же важна, как и её текущая производительность. Gecko оптимизирован для того, чтобы загружать разнообразный контент эффективно: ведь Gecko впитал в себя опыт всего Web-а! Много лет Web улучшался, а разработчики улучшали его контент. Параллельный парсинг HTML, разумное выстраивание очереди перерисовки и декодирования изображений, умные алгоритмы компоновки и т.д.. Все эти оптимизации, конечно, улучшают и производительность Firefox OS.</p> + +<div class="note"> +<p><strong>Заметка:</strong> смотрите <a href="/en-US/docs/Archive/B2G_OS/Firefox_OS_apps/Performance/Firefox_OS_performance_testing">Тестирование производительности Firefox OS</a> для дополнительной информации о Firefox OS спецификациях, которые помогают оптимизировать производительность запуска.</p> +</div> + +<h2 id="Производительность_приложений">Производительность приложений</h2> + +<p>Эта секция попытается ответить на вопрос "как сделать приложение быстрее?".</p> + +<h3 id="Скорость_загрузки">Скорость загрузки</h3> + +<p>Загрузка приложения может быть поделена на три этапа, которые влияют на UPP:</p> + +<ul> + <li>Первая отрисовка. Момент, когда приложение загрузило достаточно данных и ресурсов, чтобы отрисовать первый - начальный - кадр</li> + <li>Начало интерактивности - например, когда пользователю становится доступна возможность нажать кнопку, а приложение может ему ответить</li> + <li>Полная загрузка - например, когда все пользовательские альбомы перечислены в музыкальном плеере</li> +</ul> + +<p>Секрет быстрой загрузки требует двух вещей: UPP (ощущаемая пользователем скорость) - это единственное, что имеет значение; эта скорость зависит от критического пути рендеринга (Critical Rendering Path). Критический путь - это единственный и необходимый код, который должен запускать перечисленные выше события.</p> + +<p>Например, отрисовка первого кадра, который содержит в себе необходимый HTML и CSS включает:</p> + +<ol> + <li>Браузер должен спарсить HTML</li> + <li>DOM должен быть построен для этого HTML</li> + <li>Ресурсы (изображения, видео и др.) для этой модели DOM должны быть загружены и декодированы</li> + <li>CSS стили должны быть применены к DOM и должен быть сформирован CSSOM</li> + <li>Стилизованный компонент должен быть подготовлен к рендеру</li> +</ol> + +<p>В этом списке вы не увидите "загрузить JS файл, который нужен для второстепенного меню", "забрать и декодировать изображения для списка достижений" и т.п. Эта работа не должна выполняться при запуске приложения.</p> + +<p>Звучит очевидно, но для достижения лучшей воспринимаемой скорости загрузки нужно запускать только тот код, который необходим и критичен для запуска приложения. Короткий путь увеличивает скорость.</p> + +<p>Web-платформа очень динамична. JavaScript - это динамически типизированный язык, а Web разрешает загружать код, HTML, CSS, изображения и другие ресурсы динамически. Эти функции могут быть использованы для того, чтобы отложить загрузку ресурсов; чтобы сократить критический путь, подвинув загрузку лишнего контента на несколько моментов позже. Такой подход называется "ленивой загрузкой".</p> + +<p>Другая проблема, которая может привести к ненужному простою - это ожидание ответа на запросы (например, запрос к базе данных). Чтобы избегать этой проблемы, приложение должно запрашивать данные как можно раньше, еще во время запуска программы. Тогда к моменту, когда данные понадобятся - они уже будут в системе и приложению не придется ждать.</p> + +<div class="note"> +<p><strong>Заметка: </strong>Для дополнительной информации об ускорении запуска ознакомьтесь с <a href="/en-US/Apps/Developing/Performance/Optimizing_startup_performance">Optimizing startup performance</a>.</p> +</div> + +<p>Следует также отметить, что ресурсы, закешированные локально, могут быть загружены гораздо быстрее, чем динамические данные, загруженные через мобильную сеть с её задержками или узким каналом. Локальное кеширование и работа в оффлайне могут быть достигнуты с помощью <a href="/en-US/docs/">Service Workers</a>. См. <a href="/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers">Making PWAs work offline with Service workers</a> для подробностей.</p> + +<h3 id="Частота_кадров_2">Частота кадров</h3> + +<p>Первая важная вещь для высокой частоты кадров - это выбор правильного инструмента. Используйте HTML и CSS для создания контента, который будет в основном статическим, прокручиваемым и редко анимируемым. Используйте Canvas для создания высокодинамичного контента, например, игр, которые требуют серьезного контроля рендеринга и не нуждаются в темах.</p> + +<p>При отрисовывании контента в Canvas, разработчик должен сам позаботиться о достижении целей по частоте кадров, ведь он получает полный контроль над всем, что отрисовывается.</p> + +<p>При использовании HTML и CSS разработчику необходимо использовать правильные примитивы. Firefox очень хорошо оптимизирован для скролла любого контента. Обычно это не является проблемой. Но очень часто, разменивая качество и стабильность на скорость, мы идём на ухищрения, которые могут "переоптимизировать" страницу так, что частота кадров будет выше нужной нам. Так как глаз все равно слабо различает FPS больше 60, нет необходимости в таких оптимизациях. Одна из таких оптимизаций - использование статического рендера вместо CSS-градиента. В некоторых случаях это излишне. Чтобы не применять оптимизацию, вы можете воспользоваться CSS <a href="/en-US/docs/Web/Guide/CSS/Media_queries">media queries</a>, которые позволят использовать подобные решения только для конкретных устройств.</p> + +<p>Множество приложений используют Transitions и Animations для перехода между страницами или панелями. Например, когда пользователь нажимает кнопку "Настройки", чтобы перейти на другой экран; или для вызова поп-апа. Firefox оптимизирован для выполнения переходов и анимаций для сцен, которые:</p> + +<ul> + <li>Используют страницы/панели равные по размеру дисплею или меньше</li> + <li>Используют для переходов/анимаций свойства <code>Transform</code> и <code>Opacity</code></li> +</ul> + +<p>Переходы и анимации, которые придерживаются этих правил, будут выгружены в системный компоновщик и выполнены максимально эффективно.</p> + +<h3 id="Использование_памяти_и_энергии">Использование памяти и энергии</h3> + +<p>Проблема улучшения использования памяти и энергии так же важна для ускорения запуска: не делайте ненужную работу и не загружайте ненужные ресурсы. Используйте эффективные структуры данных и уделяйте внимание оптимизации ресурсов.</p> + +<p>Современные ЦПУ могут работать в режиме энергосбережения, когда они не задействованы. Приложения, которые постоянно запускают таймеры или продолжают ненужные анимации, мешают процессору перейти в режим энергосбережения. Эффективные приложения не должны так делать.</p> + +<p>Когда приложение переходит в фоновый режим, срабатывает событие {{event("visibilitychange")}}. Это событие - друг разработчика. Приложения должы слушать его и реагировать на него. Например, в Firefox OS, приложения, которые умеют ограничивать использование ресурсов и экономят память, когда переходят в фоновый режим, с меньшей долей вероятности будут отключены (см. заметку ниже). Это, если посмотреть с другой стороны, означает, что раз приложение не было выгружено - оно будет быстрее загружено.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Как было упомянуто выше, Firefox OS пытается сохранить как можно больше приложений, но иногда вынуждена приостанавливать некоторые из них. Обычно это происходит, когда у устройства заканчивается память. Чтобы узнать больше о том, как Firefox OS управляет памятью и избавляется от приложений, когда начинаются проблемы с памятью, читайте <a href="/en-US/docs/Archive/B2G_OS/Debugging/Debugging_OOMs">Debugging out of memory errors on Firefox OS</a>.</p> +</div> + +<h3 id="Советы_к_применению_в_коде">Советы к применению в коде</h3> + +<p>Следующие советы помогут вам улучшить один или несколько факторов производительности, которые мы обсуждали ранее.</p> + +<h4 id="Используйте_CSS_animation_и_transition">Используйте CSS animation и transition</h4> + +<p>Вместо использования функции <code>animate()</code> какой-нибудь библиотеки, которая, вероятно, использует много плохих решений (например ({{domxref("window.setTimeout()")}} или анимирование top / left), используйте <a href="/en-US/docs/Web/Guide/CSS/Using_CSS_animations">CSS анимации</a>. Во многих случаях, вы можете использовать <a href="/en-US/docs/Web/Guide/CSS/Using_CSS_transitions">CSS Transitions</a>. Использование этих свойств поможет, так как браузер спроектирован так, чтобы оптимизировать эти эффекты и переносить часть вычислений на GPU, чтобы они работали плавно и с минимальным влиянием на процессор. Другое преимущество - вы можете определить эти анимации в CSS декларативным образом, а не в бизнес-логике приложения.</p> + +<p>CSS анимации дают вам очень точный контроль эффектов, если вы используете <a href="/en-US/docs/Web/CSS/@keyframes">keyframes</a>. Более того, вы сможете отслеживать события, которые происходят во время анимации, так как основной поток обработки не блокируется. Вы можете с легкостью запускать анимации с помощью {{cssxref(":hover")}}, {{cssxref(":focus")}} или {{cssxref(":target")}}. Или динамически добавляя или удаляя классы элемента.</p> + +<p>Если вы хотите создавать анимации "на лету" или изменять их с помощью JavaScript, Джеймс Лонг написал простую библиотеку для этого - <a href="https://github.com/jlongster/css-animations.js/">CSS-animations.js</a>.</p> + +<h4 id="Используйте_CSS_трансформацию">Используйте CSS трансформацию</h4> + +<p>Вместо того, чтобы изменять абсолютное позиционирование и возиться с этой математикой вручную, используйте свойство {{cssxref("transform")}}, чтобы изменить позицию, масштаб и некоторые другие аспекты вашего контента. Именно так вы используете аппаратное ускорение. Браузер умеет передавать такие задачи графическому процессору, давая возможность ЦПУ заняться другими важными вещами.</p> + +<p>К тому же, трансформация даёт возможности, которых в ином случае у вас не было бы. Вы не только можете манипулировать элементом в двумерном пространстве, но можете трансформировать его в 3D, изменять его наклон (скашивать, skew), поворачивать и др. Пол Айриш опубликовал статью <a href="https://paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/">in-depth analysis of the benefits of <code>translate()</code></a>, в которой проанализировал работу translate с точки зрения производительности. Используя translate/transform вы используете правильный декларативный инструмент и возлагаете оответственность за его оптимизацию на браузер. Вы так же получаете возможность с легкостью позиционировать элементы. Если вы будете использовать только <code>top</code> и <code>left</code>, вам придется написать некоторый дополнительный код, чтобы предусмотреть некоторые особенности такого позиционирования. И последний бонус - с Transform / Translate вы будете работать примерно так же, как работали бы с элементом <code>canvas</code>.</p> + +<div class="note"> +<p><strong>Заметка:</strong> В некоторых случаях (в зависимости от платформы) вам может понадобиться добавить свойство <code>translateZ(0.1)</code>, если вы хотите заставить клиента перенести вычисление анимаций на графический адаптер. Как было упомянуто выше, это может улучшить производительность, но увеличит потребление памяти. Какое из зол - меньшее - решать вам. Протестируйте оба варианта и выясните, что лучше подходит для вашего приложеия.</p> +</div> + +<h4 id="Используйте_requestAnimationFrame_вместо_setInterval">Используйте <code>requestAnimationFrame()</code> вместо <code>setInterval()</code></h4> + +<p>Вызовы {{domxref("window.setInterval()")}} запускают код с учётом предполагаемой частоты кадров. Однако, эта ожидаемая частота и фактическая не всегда совпадают. SetInternal говорит браузеру "нарисуй результаты", даже если браузер не занимается сейчас отрисовкой - такое случается, когда графический адаптер ещё не дошел до следующего цикла обновления экрана. Такое несовпадение таймингов - чрезмерная растрата процессорного времени и даже может приводить к снижению срока службы аккумуляторов пользовательского устройств.</p> + +<p>Вместо этого, вам необходимо использовать {{domxref("window.requestAnimationFrame()")}}. Эта функция ждет, пока клиент не будет готов к формированию следующего кадра анимации и не будет досаждать своими запросами аппаратную часть устройства, если устройство не занимается в данный момент рендерингом. Другое преимущество этого API в том, что такие анимации не будут запускаться, пока ваше приложение не видно на экране (например, если оно выполняется в фоне или занимается другими операциями). Это сохранит батарею и защитит вас от проклятий, которые пользователи будут выкрикивать в небо.</p> + +<h4 id="Делайте_события_мгновенными">Делайте события мгновенными</h4> + +<p>Как старомодные, заботящиеся о доступности веб-разработчики, мы любим событие нажатия, так как оно также срабатывает и для ввода с клавиатуры. На мобильных устройствах это работает иначе. Вы должны использовать {{event("touchstart")}} и {{event("touchend")}}, а не click. Причина этому - в мобильных устройствах срабатывает задержка в несколько сотен миллисекунд между касанием экрана и запуском обработчика click. Из-за этого приложение может ощущаться медленным. Если вы будете тестировать ваше приложение на предмет работы с касаниями, вы не пожертвуете доступностью. Кроме того, существуют библиотеки, которые ускорят разработку. Например, Financial Times использует библиотеку <a href="https://github.com/ftlabs/fastclick">fastclick</a> для обработки.</p> + +<h4 id="Держите_интерфейс_простым">Держите интерфейс простым</h4> + +<p>Одна из самых больших проблем, которую мы нашли в HTML5 приложениях, заключается в том, что перенос большого количества <a href="/en-US/docs/DOM">DOM</a> элементов делает приложение медленным - особенно, если в этих элементах много градиентов и теней. Упрощайте то, как выглядит ваше приложение и передвигайте проксирующий элемент, когда выполняете Drag And Drop - это сильно ускорит работу.</p> + +<p>Когда, например, у вас есть большой список элементов (скажем, твитов), не перемещайте их все. Вместо этого, держите в вашем DOM-дереве только те элементы, которые видимы и несколько за областью видимости, чтобы при скролле не было заметно моргание. Остальные - прячьте. Сохраняйте данные в JavaScript объектах, вместо хранения данных и доступа к ним в DOM. Думайте об экране, как об устройстве представления необходимых данных, а не всех. Это не означает, что вы не можете использовать HTML, как источник данных; просто читайте его один раз, а затем продвигайтесь на 10 элементов, изменяя содержимое первого и последнего элемента, согласно их позициям в списке, вместо того, чтобы двигать 100 элементов, которые уже невидимы. Подобный трюк сработает и в играх со спрайтами: если они не видны на экране, нет необходимости запрашивать их. Вместо этого переиспользуйте элементы, которые выходят за пределы экрана, в то время как новые входят.</p> + +<h2 id="Общий_анализ_производительности">Общий анализ производительности</h2> + +<p>Firefox, Chrome и другие браузеры предоставляют встроенные инструменты, которые могут помочь вам диагностировать медленный рендеринг. В частности, <a href="/en-US/docs/Tools/Network_Monitor">Firefox's Network Monitor</a> покажет точное время, когда произошел каждый сетевой запрос, насколько большим он был и как долго обрабатывался.</p> + +<p><img alt="The Firefox network monitor showing get requests, multiple files, and different times taken to load each resource on a graph." src="https://mdn.mozillademos.org/files/6845/network-monitor.jpg" style="display: block; height: 713px; margin: 0px auto; width: 700px;"></p> + +<p>Если на вашей странице есть JavaScript, который выполняется очень долго, <a href="/en-US/docs/Tools/Profiler">JavaScript profiler</a> укажет на наиболее медленные строки кода.</p> + +<p><img alt="The Firefox JavaScript profiler showing a completed profile 1." src="https://mdn.mozillademos.org/files/6839/javascript-profiler.png" style="display: block; height: 433px; margin: 0px auto; width: 896px;"></p> + +<p>Встроенный<a href="/en-US/docs/Performance/Profiling_with_the_Built-in_Profiler"> Gecko Profiler</a> - очень полезный инструмент, который позволяет вам получить ещё более подробную информацию о том, какие части кода работают медленно. Это довольно сложный инструмент, но он предоставляет множество деталей.</p> + +<p><img alt="A built-in Gecko profiler windows showing a lot of network information." src="https://mdn.mozillademos.org/files/6837/gecko-profiler.png" style="display: block; height: 514px; margin: 0px auto; width: 896px;"></p> + +<div class="note"> +<p><strong>Заметка:</strong> Вы можете использовать эти инструменты и в Android браузере, запустив Firefox и включив <a href="/en-US/docs/Tools/Remote_Debugging">remote debugging</a>.</p> +</div> + +<p>Например, множественные сетевые запросы в мобильной сети занимают больше времени. Рендеринг больших изображений и CSS градиентов может происходить дольше. Простое скачивание больших изображений может занять большее время, даже через быструю сеть, так как аппаратная часть мобильных устройств зачастую слишком медленна, чтобы использовать все возможности быстрых каналов данных. Для получения полезных подсказок о производительности на мобильных устройствах, ознакомьтесь с докладом Максимилиано Фёртмана <a href="http://www.slideshare.net/firt/mobile-web-high-performance">Mobile Web High Performance</a>.</p> + +<h3 id="Тестовые_кейсы_и_сообщения_об_ошибках">Тестовые кейсы и сообщения об ошибках</h3> + +<p>Если инструменты разработчика в Firefox или Chrome не помогают вам выяснить проблему или выглядит так, что браузеры сами по себе создают проблему, попробуйте сформировать тестовое окружение, которое максимально изолирует проблему. Это очень часто помогать диагностировать проблему.</p> + +<p>Убедитесь, что вы можете воспроизвести проблему, просто сохраняя и загружая статическую копию HTML-страницы (включая изображения/стили/скрипты). Если так - удалите из HTML файла всю личную информацию и обратитесь к за помощью (отправьте отчет в <a href="https://bugzilla.mozilla.org/">Bugzilla</a> или, например, сохраните файл на своем сервере и поделитесь ссылкой). Вам также понадобится поделиться информацией профилировщика, которую вы собрали с помощью инструментов отладки.</p> diff --git a/files/ru/web/performance/производительность_анимации/index.html b/files/ru/web/performance/производительность_анимации/index.html new file mode 100644 index 0000000000..8d8054dade --- /dev/null +++ b/files/ru/web/performance/производительность_анимации/index.html @@ -0,0 +1,174 @@ +--- +title: Производительность анимации и частота кадров +slug: Web/Performance/Производительность_анимации +tags: + - CSS animation + - Developer Tools + - Web Performance + - Анимация + - Производительность + - инструменты +translation_of: Web/Performance/Animation_performance_and_frame_rate +--- +<p>Анимация в Вебе может быть сделана с помощью {{domxref('SVGAnimationElement', 'SVG')}}, {{domxref('window.requestAnimationFrame','JavaScript')}}, включая {{htmlelement('canvas')}} и {{domxref('WebGL_API', 'WebGL')}}, CSS {{cssxref('animation')}}, {{htmlelement('video')}}, анимированных GIF и даже с помощью анимированных PNG и других типов изображений. Производительность CSS анимации может отличаться от одного CSS-свойства к другому, а попытка анимировать некоторые "дорогие" CSS-свойства может привести к зависаниям ({{glossary('jank')}}), даже несмотря на то, что браузер борется за то, чтобы смягчить частоту смены кадров {{glossary('frame rate')}}.</p> + +<p>Для анимированных медиа, таких как видео и GIF, основная проблема производительности - это размер файлов. Скачивание больших по объему файлов не может не повлиять на производительность системы или на то, как эту систему воспринимает пользователь. </p> + +<p>Анимации, основанные на коде, будь то CSS, SVG, <canvas>, webGL или другие JavaScript анимации, могут нести проблемы производительности сами в себе, даже если файлы этого кода скачиваются быстро. Такие анимации могут потреблять всё время CPU и приводить к зависаниям.</p> + +<p>Несомненно, производительность каждой конкретной системы - очень чувствительная тема. Улучшив клиентскую производительность, вы сможете не только ускорить работу приложения, но даже затронете физический аспект - сможете сэкономить заряд батареи мобильных устройств и / или понизите температуру устройства. Поэтому очень важно владеть инструментами для измерения производительности. Они помогут вам понять всю работу, которую проводит браузер, пока рендерит ваше приложение и поможет избежать и диагностировать проблемы, когда они происходят.<br> + <br> + Пользователи ожидают, что взаимодействие с интерфейсом будет плавным, а интерфейс будет отзывчивым. Анимация помогает улучшить восприятие приложения, сделав его быстрым и отзывчивым; но анимация так же может замедлить его и привести к зависаниям, если она сделана неумело. Отзывчивые интерфейсы должны иметь частоту смены кадров, равную <a href="/en-US/docs/Tools/Performance/Frame_rate">60 кадров в секунду (fps)</a>. В то время, как не всегда возможно поддерживать такую частоту, очень важно поддерживать быструю и устойчивую смену кадров для анимации. </p> + +<p>Мы рассмотрим, как можно использовать инструменты браузера для инспектирования частоты смены кадров. Так же, мы обсудим некоторые подсказки, как организовать и поддерживать быструю и стабильную смену кадров.</p> + +<p>Графики <a href="/en-US/docs/Tools/Performance/Frame_rate">frame rate</a> и <a href="/en-US/docs/Tools/Performance/Waterfall">waterfall</a> из встроенных инструментов браузера дают информацию о том, как браузер выполняет работу по анимации. Используя эти инструменты, вы можете измерить fps приложения и диагностировать узкие места, в которых fps уменьшается.</p> + +<p>С помощью <a href="/en-US/docs/Web/Guide/CSS/Using_CSS_animations">CSS анимации</a> вы указываете <a href="/en-US/docs/Web/CSS/@keyframes">ключевые кадры (keyframes)</a>, каждый из которых использует определенные CSS свойства, чтобы определить внешний вид элемента в конкретный (ключевой) момент анимации. Браузер создает анимации с помощью плавных переходов от одного ключевого кадра к следующему.</p> + +<p>Если сравнивать анимацию с помощью JavaScript и CSS, вы увидите, что CSS-анимации проще создать. Более того, CSS-анимации гарантируют лучшую производительность, так как они автоматически делегируют некоторые задачи браузеру. Например, в случае CSS браузер сам решает, когда нужно отрендерить кадр, а когда пропустить кадр, если это необходимо. </p> + +<p><br> + Однако, стоимость изменения разных CSS свойств варьируется. Общепринято, что 60 кадров в секунду - это достаточная частота, чтобы анимация выглядела мягкой и плавной. Несложный подсчет говорит, что при частоте 60 кадров в секунду, браузер имеет лишь 16.7 миллисекунд, чтобы выполнить все скрипты, пересчитать стили, скомпоновать слои и отрисовать новый кадр. Отсюда следует, что медленные скрипты и анимация дорогих CSS свойств может может привести к <a href="/en-US/docs/Glossary/Jank">зависаниям</a>, так как браузер все еще будет пытаться вычислить все 60 кадров.</p> + +<p>Стоит заметить, что 60 кадров в секунду - это стандартная частота обновления экрана. Существуют экраны с гораздо большим FPS. Например, экраны игровых ноутбуков или iPad Pro 2018 имеют частоту смены кадров, равную 120 fps и выше. Для таких устройств производители браузеров ограничивают частоту 60-ю кадрами в секунду, но с помощю некоторых опций этот лимит можно убрать. И в этом случае, на формирование каждого кадра устройство будет отводить лишь 8.6 миллисекунд.</p> + +<h2 id="Этапы_рендеринга">Этапы рендеринга</h2> + +<p>Процесс, используемый браузером для отображения анимации CSS свойств, может быть представлен как последовательность этапов из следующего изображения:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10821/css-rendering-waterfall.png" style="display: block; height: 203px; margin-left: auto; margin-right: auto; width: 546px;"></p> + +<ol> + <li><strong>Recalculate Style</strong>: когда любое CSS свойство для элемента изменяется, браузер должен заново вычислить результирующий набор свойств.</li> + <li><strong>Layout</strong>: затем браузер использует вычисленные стили для того, чтобы понять позицию и геометрию элементов - как измененного, так и рядом лежащих. Эта операция называется "layout", но иногда её так же называют "reflow".</li> + <li><strong>Paint</strong>: наконец, браузер должен перерисовать элементы на экране. Но этот этап не обязательно должен быть простым, как на изображении. Страница может быть разделена на слои, каждый из которых перерисовывается независимо, а только после этого они комбинируются в процессе, который называется композицией "Composition".</li> +</ol> + +<p>Процессы, которые браузер использует для отрисовывания изменений на элементе <canvas> отличаются. В случае <canvas>, Layout не присходит. Скорее, страница будет перерисована с помощью JavaScript canvas API. </p> + +<p>В любом случае, вычисление каждого следующего кадра должно происходить достаточно быстро, чтобы успеть попасть в частоту обновления экрана, чтобы не было зависаний.</p> + +<h2 id="Стоимость_CSS_свойств">Стоимость CSS свойств</h2> + +<p>На всех этапах рендеринга изменение некоторых свойств является более затратным, других - менее:</p> + +<table class="fullwidth-table standard-table"> + <thead> + <tr> + <th scope="col">Тип свойства</th> + <th scope="col">Стоимость</th> + <th scope="col">Примеры</th> + </tr> + </thead> + <tbody> + <tr> + <td>Свойства, затрагивающие геометрию или позицию элемента, запускают <strong>весь</strong> процесс заново: новое вычисление стилей, layout и перерисовку.</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/10827/recalculate-style.png" style="height: 26px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10825/layout.png" style="height: 26px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10823/paint.png" style="height: 26px; width: 123px;"></td> + <td> + <p><code><a href="/en-US/docs/Web/CSS/left">left</a></code><br> + <code><a href="/en-US/docs/Web/CSS/max-width">max-width</a></code><br> + <code><a href="/en-US/docs/Web/CSS/border-width">border-width</a></code><br> + <code><a href="/en-US/docs/Web/CSS/margin-left">margin-left</a></code><br> + <code><a href="/en-US/docs/Web/CSS/font-size">font-size</a></code></p> + </td> + </tr> + <tr> + <td> + <p>Свойства, не затрагивающие геометрию и позиционирование элементов, но не лежащие в отдельном слое, запускают только вычисление стилей и перерисовку, но не Layout.</p> + </td> + <td><img alt="" src="https://mdn.mozillademos.org/files/10827/recalculate-style.png" style="height: 26px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10835/layout-faint.png" style="height: 52px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10823/paint.png" style="height: 26px; width: 123px;"></td> + <td> + <p><code><a href="/en-US/docs/Web/CSS/color">color</a></code></p> + </td> + </tr> + <tr> + <td> + <p>Свойства, которые рендерятся в отдельном слое не запускают даже repaint, так как результат обновления обрабатывается на этапе композиции.</p> + </td> + <td><img alt="" src="https://mdn.mozillademos.org/files/10827/recalculate-style.png" style="height: 26px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10835/layout-faint.png" style="height: 52px; width: 123px;"> <img alt="" src="https://mdn.mozillademos.org/files/10839/paint-faint.png" style="height: 26px; width: 123px;"></td> + <td><code><a href="/en-US/docs/Web/CSS/transform">transform</a></code><br> + <code><a href="/en-US/docs/Web/CSS/opacity">opacity</a></code></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p>На Веб-сайте <a href="http://csstriggers.com/">CSS Triggers</a> хорошо показано, какие CSS свойства вызывают те или иные этапы обновления в разных браузерах.</p> +</div> + +<h2 id="Пример_margin_против_transform">Пример: margin против transform</h2> + +<p>В этом разделе мы увидим, как инструмент <a href="/en-US/docs/Tools/Performance/Waterfall">Waterfall</a> может указать на разницу между анимацией. ёё <code><a href="/en-US/docs/Web/CSS/margin">margin</a></code> и <code><a href="/en-US/docs/Web/CSS/transform">transform</a></code>.</p> + +<p>Задумка этого сценария не в том, чтобы убедить вас, что анимация через <code>margin</code> - это всегда плохая идея. Сценарий нужен, чтобы продемонстрировать, как инструменты могут помочь вам понять работу браузера и как вы можете применить эти знания для оптимизации.</p> + +<p>Если вы хотите самостоятельно разобраться с этим примером, вы можете найти демо <a href="http://mdn.github.io/performance-scenarios/animation-transform-margin/index.html">здесь</a>. Демо выглядит так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/11029/css-animations-demo.png" style="display: block; height: 677px; margin-left: auto; margin-right: auto; width: 1000px;">На экране всего два контрола: кнопка "start / stop" для запуска и остановки анимации и радио-кнопки для выбора свойства, с помощью которого происходит анимация: <code>margin</code>, или <code>transform</code>.</p> + +<p>Так же на странице есть некоторое количество элементов со свойствами <code><a href="/en-US/docs/Web/CSS/linear-gradient">linear-gradient</a></code> и <code><a href="/en-US/docs/Web/CSS/box-shadow">box-shadow</a></code> Мы обращаем внимание именно на эти два свойства, так как они относительно дорогие.</p> + +<p>Так же существует видео-версия анализа и оптимизации этой страницы.</p> + +<p>{{EmbedYouTube("Tvu6_j8Qzfk")}}</p> + +<h3 id="Анимация_свойства_margin">Анимация свойства margin</h3> + +<p>Оставим включенной опцию "Use margin" и начнём анимацию. В это же время откроем "Performance tool" и нажмем кнопку "записать" (make a recording). Нам понадобится лишь пара секунд записи.</p> + +<p>Откройте первую запись. Точное содержимое, которое вы увидите, зависит от вашего устройства, системной нагрузки и окружения, но, в целом это должно выглядеть так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10853/margin-recording.png" style="display: block; height: 237px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>На экране показаны три отдельных секции: (a) обзор этапов рендеринга (Waterfall), (b) частота кадров, и (c) детали на временной шкали.</p> + +<h4 id="Обзор_этапов_рендеринга_на_временной_шкале_Waterfall">Обзор этапов рендеринга на временной шкале (Waterfall)</h4> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10857/margin-timeline-overview.png" style="display: block; height: 58px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>Сейчас здесь показаны ужатые этапы рендеринга <a href="/en-US/docs/Tools/Performance/Waterfall">Waterfall</a>. Как видите, большая часть графика заполнена зеленым цветом - это говорит нам о том, что <a href="/en-US/docs/Tools/Performance/Timeline#timeline-color-coding">мы тратим много ресурсов на отрисовывание</a>.</p> + +<h4 id="Частота_кадров_Frame_Rate">Частота кадров (Frame Rate)</h4> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10859/margin-frame-rate.png" style="display: block; height: 64px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>Эта секция показывает <a href="/en-US/docs/Tools/Performance/Frame_rate">частоту кадров</a>. Средняя частота на примере - 46.67fps. Это ниже, чем желаемые 60fps. Однако, ещё хуже то, что частота кадров нестабильна - есть этапы, где частота кадров снижается до 20 и даже до 10 fps. Маловероятно, что вы увидите здесь плавную анимацию, особенно если добавите какое-то взаимодействие с пользователем.</p> + +<h4 id="Этапы_рендеринга_в_деталях_Waterfall">Этапы рендеринга в деталях (Waterfall)</h4> + +<p>Оставшаяся часть записей показа в секции "Waterfall view". Если вы пролистаете этот список, вы увидите что-то наподобие этого:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10861/margin-timeline.png" style="display: block; height: 532px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>Это шаги рендеринга (<a href="/en-US/docs/Tools/Performance/Scenarios/Animating_CSS_properties#The_CSS_rendering_waterfall">rendering waterfall</a>). Для каждого кадра анимации мы вычисляем стили для каждого элемента, потом вычисляем Layout, а затем перерисовываем все элементы.</p> + +<p>Из таблицы видно, что особый урон производительности наносит перерисовка Paint (зелёные полосы). Например, выделенный этап Paint занял 13.11мс. Учитывая, что весь бюджет рендеринга - 16.7мс, неудивительно, что мы увидели падения fps.</p> + +<p>Вы можете поэкспериментировать с некоторыми свойствами. Например, попробуйте убрать box-shadow с помощью инспектора страницы (<a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_and_edit_CSS">Page / Element Inspector</a>), замерьте производительность и посмотрите, как это отразилось на производительности. Затраты на Paint уменьшатся значительно. Но они все ещё есть. Мы ещё вернёмся к этому вопросу позже, когда будем изучать использование <code><a href="/en-US/docs/Web/CSS/transform">transform</a></code> вместо <code><a href="/en-US/docs/Web/CSS/margin">margin</a></code>. Вы увидите, что от затрат на этот этап можно избавиться полностью.</p> + +<h3 id="Анимация_свойства_transform">Анимация свойства transform</h3> + +<p>Теперь, переключитесь на "Use transform" и запишите новые данные. Это должно выглядеть примерно так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10863/transform-recording.png" style="display: block; height: 234px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<h4 id="Обзор_этапов_рендеринга_на_временной_шкале_Waterfall_2">Обзор этапов рендеринга на временной шкале (Waterfall)</h4> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10869/transform-timeline-overview.png" style="display: block; height: 57px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>В сравнении с <a href="/en-US/docs/Tools/Performance/Scenarios/Animating_CSS_properties#Waterfall_overview">версией, которая использует margin</a>, мы видим намного меньше зеленого, но намного больше фиолетового цвета. Это говорит о том, что вместо paint мы теперь тратим ресурсы на этапы <a href="/en-US/docs/Tools/Performance/Waterfall#timeline-color-coding">layout или style recalculation</a>.</p> + +<h4 id="Частота_кадров_Frame_Rate_2">Частота кадров (Frame Rate)</h4> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10865/transform-frame-rate.png" style="display: block; height: 62px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>В сравнении с <a href="/en-US/docs/Tools/Performance/Scenarios/Animating_CSS_properties#Frame_rate">версией, которая использует margin</a>, показатели fps здесь выглядят достаточно хорошо. Средняя частота кадров близка к 60fps, а стабильность fps, за исключением падения fps в начале значительно выросла.</p> + +<h4 id="Этапы_рендеринга_в_деталях_Waterfall_2">Этапы рендеринга в деталях (Waterfall)</h4> + +<p>В этой секции мы видим объяснения тому, что fps значительно улучшился. Мы больше не тратим время на layout и перерисовку элементов. :</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10867/transform-timeline.png" style="display: block; height: 384px; margin-left: auto; margin-right: auto; width: 800px;"></p> + +<p>Здесь, используя <code>transform</code>, мы заметно улучшили производительность приложения. А инструменты разработчика помогли нам это сделать.</p> |