Асинхронная загрузка CSS и JavaScript
Асинхронная загрузка внешних CSS- и JS-ресурсов способствует увеличению скорости загрузки сайта и отображения веб-страниц в браузере, обеспечивая загрузку и выполнение файлов в фоновом режиме без блокировки рендеринга
Содержание
Прежде, чем приступать к реализации асинхронной загрузки CSS- и JS-файлов, рекомендуем ознакомиться со значением структуры кода веб-страниц по отношению к скорости загрузки сайта.
Что такое асинхронная загрузка?
Процесс отображения страницы сайта в браузере сопровождается задержками (Render Blocking) всякий раз, когда браузер обнаруживает внешние CSS- и JS-ресурсы в тегах link
и script
соответственно. Это приводит к тому, что некоторое время пользователь находится в ожидании отображения веб-страницы на экране до момента, пока не загрузятся и не выполнятся файлы, препятствующие её отображению.
Например, блок head
веб-страницы имеет следующее содержание:
<head> <title>Bootstrap Agency Template</title> <link rel="stylesheet" href="css/bootstrap.css"> <script src="js/jquery-1.11.3.min.js"></script> <script src="js/bootstrap.js"></script> </head>
Результаты анализа данной страницы в сервисе PageSpeed Insights обязательно будут содержать рекомендацию «Удалите код JavaScript и CSS, блокирующий отображение верхней части страницы»:
Это значит, что отображение страницы в браузере не начнётся, пока все внешние CSS- и JS-файлы, указанные в теге head
, не будут загружены и применены.
Во избежание задержки отображения страницы применяется асинхронная загрузка файлов CSS и JavaScript, обеспечивающая безостановочный процесс отображения страницы в браузере.
Асинхронная загрузка JavaScript
Обеспечить асинхронную загрузку JS-файлов можно с помощью атрибутов defer
или async
тега script
. В обоих случаях загрузка JS-файлов не задерживает отображение страницы, отличие заключается в моменте выполнения скрипта.
Тег SCRIPT без атрибутов (синхронная загрузка JS)
<head> <script src="jquery.js"></script> </head>
Если тег script
применяется без атрибутов defer
или async
, то загрузка скрипта задерживает процесс отображения (рендеринг) страницы до того момента, пока он не будет загружен и выполнен.
Задержка рендеринга страницы в браузере обеспечивает выполнение скриптов в порядке их указания в HTML-коде.
Тег SCRIPT с атрибутом ASYNC (асинхронная загрузка JS)
<head> <script src="jquery.js" async></script> </head>
Атрибут async
обеспечивает асинхронную загрузку внешнего JS-файла: файл будет загружен и выполнен в фоновом режиме без задержки отображения страницы.
При применении тегов script
с атрибутом async
следует помнить, что порядок выполнения скриптов (если JS-файлов несколько) не сохраняется: они будут выполняться по окончании их загрузки вне зависимости от их порядка в HTML-коде. Это может привести к ошибкам и несрабатыванию скриптов.
<head> <!-- bootstrap.js, использующий jquery.js, не будет функционировать, т. к. скрипты выполняются асинхронно --> <script src="jquery.js" async></script> <script src="bootstrap.js" async></script> </head>
Решением является объединение кода всех JS-файлов в один, или применение атрибута defer, если проблема касается только внешних файлов.
Тег SCRIPT с атрибутом DEFER (отложенная загрузка JS)
<head> <script src="jquery.js" defer></script> </head>
Атрибут defer
обеспечивает отложенную загрузку внешнего JS-файла: файл будет загружен без задержки отображения страницы и выполнен по окончанию рендеринга.
Также применение атрибута defer
, в отличие от async
, сохраняет последовательность выполнения внешних скриптов:
<head> <script src="jquery.js" defer></script> <script src="bootstrap.js" defer></script> </head>
Следует учитывать, что атрибут defer
(как и async
) не откладывает выполнение встроенных в страницу скриптов: они будут проанализированы браузером и в случае, если файл JS-библиотеки, которую они используют, не будет загружен и исполнен, то и скрипты будут проигнорированы:
<head> <script href="jquery.js" defer></script> <script> // этот скрипт использует jquery.js, и браузер его проигнорирует, // т. к. выполнение jquery.js будет отложено $(document).ready(function() { $('head').append('<link rel="stylesheet" href="style.css">'); }) </script> </head>
Для сайтов на CMS
Отличным решением обеспечения асинхронной загрузки скриптов для сайтов на Joomla, WordPress, Magento и Drupal является плагин JCH Optimize, позволяющий не только добавить атрибуты async
и defer
в теги script
, но и объединять все внешние JS-файлы в один, а также размещать их перед закрывающим тегом body
.
Асинхронная загрузка CSS
Загрузка и обработка браузером внешних файлов стилей также сопровождается блокировкой рендеринга страницы, избежать которую можно посредством их асинхронной загрузки. Сложность в том, что реализовать асинхронную загрузку CSS с помощью атрибутов тега, как это делается для JS-файлов, нельзя. Решить поставленную задачу можно различными способами с помощью JavaScript.
Посредством JS
Обеспечить асинхронную загрузку внешних CSS-файлов можно с помощью JavaScript без применения сторонних библиотек.
Для этого можно использовать следующую JS-функцию:
function asyncCSS(href) { var css = document.createElement('link'); css.rel = "stylesheet"; css.href = href; document.head.appendChild(css); }
После объявления функции в коде нужно её вызвать соответствующее количеству CSS-файлов число раз:
// В скобках указывается URL файла asyncCSS('style1.css'); asyncCSS('style2.css'); asyncCSS('style3.css');
Для применения данного способа разместите функцию и её вызов(ы) в теге script
перед закрывающим тегом body
:
<body> <script> function asyncCSS(href) { var css = document.createElement('link'); css.rel = "stylesheet"; css.href = href; document.head.appendChild(css); } asyncCSS('style1.css'); asyncCSS('style2.css'); asyncCSS('style3.css'); </script> </body>
С помощью jQuery
Если на странице применяется JS-библиотека jQuery, то для асинхронной загрузки CSS-файла можно применить следующий код:
<script> $(document).ready(function() { $('head').append('<link rel="stylesheet" href="style.css" />'); }) </script>
Данный скрипт определяет, что по окончании рендеринга страницы в блок head
необходимо вставить указанный тег link
, определяющий CSS-файл, что обеспечит его асинхронную загрузку.
Если требуется асинхронно загрузить несколько файлов стилей, нужно перечислить их в JS-функции:
<script> $(document).ready(function() { $("head").append("<link rel='stylesheet' href='style1.css'>"); $("head").append("<link rel='stylesheet' href='style2.css'>"); $("head").append("<link rel='stylesheet' href='style3.css'>"); }) </script>
Важно понимать, что для выполнения указанного скрипта необходимо обеспечить предварительную загрузку jQuery. Тег script
, содержащий ссылку на файл с jQuery, должен предшествовать указанному скрипту, иначе он не сработает, и стили не будут применены к странице:
<script href="jquery.js"></script> <script> $(document).ready(function() { $('head').append('<link rel="stylesheet" href="style.css">'); }) </script>
При этом, если JS-файл с jQuery будет загружаться асинхронно (с применением атрибута async
или defer
), то скрипт асинхронной загрузки CSS также не сработает, т. к. парсер браузера уже минует данный скрипт, не имея данных для его выполнения (jQuery в этот момент будет только на стадии загрузки):
<script href="jquery.js" async></script> <script> // Этот скрипт не будет выполнен, т. к. при асинхронной загрузке jQuery браузер продолжит обработку данных страницы $(document).ready(function() { $('head').append('<link rel="stylesheet" href="style.css">'); }) </script>
Чтобы асинхронно загрузить JavaScript (jQuery) и CSS, можно применить следующий приём:
<script> var js = document.createElement('script'); js.src = 'jquery.js'; // в кавычках ссылка на файл с jQuery document.head.appendChild(js); js.onload = function() { $('head').append('<link rel="stylesheet" href="style.css">'); }; </script>
С помощью скрипта headJS
Существует ряд скриптов, созданных для реализации асинхронной загрузки как CSS-файлов, так и JS-файлов. Одним из таких скриптов является headJS.
Для его применения нужно скачать JS-файл и подключить его к странице:
<script href="head.load.js"></script>
После чего необходимо перечислить URL-адреса файлов в следующем JS-коде:
head.load(['css/style.css','script-1.js','script-2.js'])
Все перечисленные файлы будут асинхронно загружены и выполнены в указанном порядке.
Данный код нужно разместить в тег script
. В коде страницы данный метод может выглядеть следующим образом:
<body> <!-- Контент --> <script href = "head.load.js"></script> <script> head.load(['css/style.css','script-1.js','script-2.js']) </script> </body>
Чтобы загружать асинхронно в том числе скрипт headJS, можно применить следующий способ:
<script> var js = document.createElement("script"); js.src = "/js/head.load.js"; // в кавычках ссылка на файл с headJS document.head.appendChild(js); js.onload = function() { head.load(['css/style.css','script-1.js','script-2.js']) }; </script>
Т. к. все перечисленные способы реализации асинхронной загрузки CSS-файлов реализуются посредством JavaScript, для подстраховки в код желательно вставить ссылки на эти файлы в теге noscript
на случай, если браузер не выполняет JS-код:
<noscript> <link rel="stylesheet" href="style.css"> </noscript>
Отложенная загрузка стилей
Каждый из предложенных способов откладывает загрузку стилей, в результате сперва происходит отрисовка страницы без их применения, после чего стили резко применяются, преображая страницу.
Во избежание этого нежелательного визуального эффекта необходимо извлечь из файлов стилей некоторое число CSS-свойств для HTML-элементов, формирующих видимую верхнюю часть страницы, и разместить их в теге style
в блоке head
.
Для сайтов на CMS
Обеспечить асинхронную загрузку CSS для сайтов на Joomla, WordPress, Magento и Drupal можно с помощью платной версии плагина JCH Optimize.
Плагин JCH Optimize Pro способен:
- объединить все внешние CSS-файлы страницы в один;
- включить встроенные (inline) CSS-правила в объединённый файл;
- извлечь CSS-правила для элементов, формирующих верхнюю часть страницы, и поместить их в тег
style
внутри блокаhead
для быстрой отрисовки видимой части страницы; - обеспечить асинхронную загрузку CSS-файла с помощью JavaScript, разместив скрипт перед закрывающим тегом
body
; - разместить ссылку на объединённый CSS-файл в теге
noscript
на случай, если браузер не обрабатывает JS.
Выводы и заключение
Асинхронная загрузка:
- JS- и CSS-файлов ускоряет загрузку и отображение страниц сайта;
- JS-файлов обеспечивается с помощью атрибутов
async
(с безотложным выполнением кода) илиdefer
(с отложенным выполнением); - файлов JS-библиотек посредством атрибута
async
иdefer
может повлечь неисполнение встроенных скриптов, использующих эти библиотеки; - файлов JS-библиотек посредством атрибута
async
также может повлечь неисполнение внешних JS-файлов, использующих методы этих библиотек; - CSS-файлов реализуется посредством JavaScript;
- асинхронная загрузка для сайтов на CMS осуществляется посредством сторонних расширений.