HeadJS или полностью асинхронная загрузка сайта

Один из самых важных показателей для современного сайта — как можно более быстрая загрузка и начало показа содержимого. Чтобы этого достичь, нужно устранить задержки, связанные с ожиданием подгрузки внешних ресурсов, сделав их асинхронными. Прежде я уже писал, как можно сделать асинхронными виджеты социальных сетей. Но недавно я нашел скрипт, который позволяет сделать асинхронной загрузку всех JavaScript и CSS-файлов, используемых на сайте. Называется он HeadJS, и кроме асинхронной загрузки имеет умеет еще делать feature detection, с помощью чего можно загружать скрипты выборочно в зависимости от возможностей устройства, с которого зашел пользователь.

Допустим, что у нас есть достаточно простой сайт с одним стилевым файлом style.css и одним скрипт-файлом mysite.js, использующим jQuery. В этом случае секция head будет выглядеть примерно так:

<head>
<link rel="stylesheet" type="text/css" href="/style.css" />
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/mysite.js"></script>
<script type="text/javascript">new MySite(); // запуск основного скрипта</script>
</head>

Хотя современные броузеры умеют качать файлы параллельно, отображение сайта произойдет только после того, как загрузится самый большой из них (скорее всего, это будет jquery.js). 
Теперь подключим HeadJS. Для этого зайдем на headjs.com и скачаем оттуда файл head.load.js. Теперь секция head приобретет такой вид: 

<head>
<noscript><link rel="stylesheet" type="text/css" href="/style.css" /></noscript>
<script type="text/javascript" src="/js/head.load.js"></script>
<script type="text/javascript">head.load(['/style.css','/js/jquery.js','/js/mysite.js'], function() {
 new MySite();
});
</script></head>

Теперь задержка уменьшилась, так как отображение сайта откладывается только до момента, когда будет загружен head.load.js, который занимает всего 2.1 Kb в сжатом виде вместо почти сотни килобайт jQuery.js, а дальше все происходит асинхронно. В функцию head.load передаются два параметра: первый — массив с файлами, которые нужно загрузить, второй — функция, которая будет вызвана после окончания загрузки (параметр не обязательный). Тег link внутри noscript остается на случай, если у пользователя отключен JavaScript.

Но можно пойти и еще дальше: сделать асинхронной загрузку самого head.load.js. Тогда секция head будет выглядеть следующим образом:

<head>
<noscript><link rel="stylesheet" type="text/css" href="/style.css" /></noscript>
<script type="text/javascript" async="async">
var script = document.createElement("script");
script.src="'/js/head.load.min.js";
script.onload=function() { head.load(['/style.css','/js/jquery.js','/js/mysite.js'], function() {
  new MySite();
})};
document.getElementsByTagName("head")[0].appendChild(script);
</script></head>

В этом случае загрузка вообще всех скриптов, используемых на сайте, идет параллельно отображению контента без блокировки. Однако это может давать весьма неприятный визуальный эффект: страница начинает отображаться, потом тут же перерисовывается. Чтобы его уменьшить, рекомендуется прописать несколько наиболее критичных стилей внутри секции head. Обычно я прописываю стили для тега body (нулевые margin и padding, а также свойства шрифта) и тега, в который обернут весь контент (для него имеет смысл указать  ширину и margin: auto).

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