Асинхронная загрузка 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, блокирующий отображение верхней части страницы»:

Рекомендация PageSpeed Insights
Рекомендация PageSpeed Insights

Это значит, что отображение страницы в браузере не начнётся, пока все внешние CSS- и JS-файлы, указанные в теге head, не будут загружены и применены.

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

Асинхронная загрузка JavaScript

Обеспечить асинхронную загрузку JS-файлов можно с помощью атрибутов defer или async тега script. В обоих случаях загрузка JS-файлов не задерживает отображение страницы, отличие заключается в моменте выполнения скрипта.

Тег SCRIPT без атрибутов (синхронная загрузка JS)

<head>
	<script src="/jquery.js"></script>	
</head>

Если тег script применяется без атрибутов defer или async, то загрузка скрипта задерживает процесс отображения (рендеринг) страницы до того момента, пока он не будет загружен и выполнен.

Синхронная загрузка JS
Синхронная загрузка JS

Задержка рендеринга страницы в браузере обеспечивает выполнение скриптов в порядке их указания в HTML-коде.

Тег SCRIPT с атрибутом ASYNC (асинхронная загрузка JS)

<head>
	<script src="/jquery.js" async></script>
</head>

Атрибут async обеспечивает асинхронную загрузку внешнего JS-файла: файл будет загружен и выполнен в фоновом режиме без задержки отображения страницы.

Асинхронная загрузка JS (атрибут async)
Асинхронная загрузка JS (атрибут async)

При применении тегов 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-файла: файл будет загружен без задержки отображения страницы и выполнен по окончанию рендеринга.

Отложенная загрузка JS (атрибут defer)
Отложенная загрузка JS (атрибут defer)

Также применение атрибута 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 осуществляется посредством сторонних расширений.

Ссылки

Автор:
Оцените материал:
5.0/5

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