Делаем все скрипты сайта асинхронными без дополнительных фреймворков

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

Но для программиста синхронность — это последовательная цепь событий, когда за 1-м событием следует 2-е, а за 2-м — 3-е, но никак вдруг 3-е событие не выполнится раньше 2-го, даже если устанет ждать его окончания. Соответственно, асинхронность для программиста означает, что события выполняются параллельно, и возможно, что 3-е событие выполнится раньше 2-го и даже раньше 1-го. Посмотрим теперь, что синхронность и асинхронность значат для наших сайтов.

Если на вашем сайте используется конструкция вида:

<script src="..."></script>

А она наверняка используется раз 5-10. То браузер задерживает отрисовку страницы на этом месте и ждёт загрузки скрипта по ссылке. Иногда это может быть полезно. Например, у вас на сайте установлен JS-счётчик просмотров статей:

<script src="..."></script>
<script>document.write( view_count )</script>

Ваш скрипт при вызове устанавливает значение переменной view_count, которую вы далее выводите. Но, если вы будете использовать асинхронный код, то получите не количество просмотров, а ошибку. Потому что на загрузку вашего скрипта, указанного по ссылке src="...", понадобится время, так что document.write будет выполнен ещё до того, как будет задана переменная view_count.

Пример со счётчиком гипотетический, но есть абсолютно реальные коды AdSence, виджетов ВКонтакте и прочие, которые чаще всего используются на сайтах как раз в синхронном варианте. Посмотрим, как это выглядит на практике.

Макет сайта

Допустим, у вас такой макет сайта, как показано на картинке. Где-то в тексте статьи или даже в её начале вы установили рекламу Google Adsense, потому что в этом месте она имеет максимальный CTR. Конечно, реклама при каждом показе страницы запрашивается с адресов Google. Происходит это обычно быстро, потому что большинство людей уже давно не пользуются модемным интернетом. Но у тех посетителей сайта, которые имеют нестабильное соединение, рекламный код загружается иногда и по несколько минут. А если на странице несколько рекламных блоков, а в конце ещё и форма комментариев ВКонтакте? Хотелось бы, чтобы посетитель не имел проблем с просмотром сайта, а определённый виджет отображался бы, как только будет загружен его код.

Идёт загрузка

Но происходит иначе. Посетитель видит такой вот «сломанный» сайт до тех пор, пока не будет получен код рекламного блока. Обычно это лишь несколько секунд (даже этого хотелось бы избежать), а бывает, что и несколько минут. Конечно, такое обстоятельство не способствует уменьшению показателя отказов. Не считаете ли вы такую цену слишком высокой за сомнительную радость посетителя во что бы то ни стало посмотреть рекламное объявление?

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

Организация асинхронности

В спецификации элемента script сказано, что достаточно указать атрибут async, чтобы скрипт загрузился асинхронно и выполнился сразу же после загрузки. Есть ещё атрибут defer — с ним скрипт тоже загружается асинхронно, но выполняется после загрузки страницы. Ура?! Не совсем. Объясню на примере виджета группы ВКонтакте. Вот его код, в котором я к вызову скрипта добавил атрибут async:

<script type="text/javascript" src="http://vk.com/js/api/openapi.js" async></script>
<script type="text/javascript">
VK.Widgets.Group( "vk_groups_...", { mode: 0, width: "165", height: "360" }, 485... );
</script>

Конечно, пример не рабочий (и не только из-за многоточий). Просто, к моменту обработки браузером строки «VK.Widgets.Group ( ... )» не будет ещё создан объект «VK» — он будет создан только после загрузки и выполнения «openapi.js», но тогда прорисовка страницы уже уйдёт вперёд. Если только мы не вызовем функцию VK.Widgets.Group( ... ) после того, как будет загружен скрипт «openapi.js». Но как определить этот момент? Даже если мы поместим вызов функции в самый конец страницы, не факт, что браузер успеет загрузить скрипт до того, как дорисует страницу до конца. Скажу более: эта статья как раз создана для того, чтобы браузер отрисовывал вашу страницу за доли секунды!

Асинхронный код виджета группы ВКонтакте

Победить созданную задачу поможет вот этот код:

<div id="vk_groups"></div>
<script type="text/javascript" src="http://vk.com/js/api/openapi.js" async></script>
<script type="text/javascript">
( function start() {
	if ( window.VK ) {
		VK.Widgets.Group( "vk_groups", { ваши_параметры }, ваш_id );
	} else setTimeout( start, 500 );
} )();
</script>

Принцип прост, как первый советский трактор. Мы выполняем проверку существования объекта «VK» в нашем окне, и если его ещё нет (значит, скрипт ВК ещё не загрузился), то назначаем повторную проверку через полсекунды. А когда при очередной проверке мы обнаружим объект «VK», вызовем функцию отображения группы ВКонтакте. Если вы правильно указали «ваши_параметры» и «ваш_id» (их скопируйте из оригинального кода, полученного на сайте vk.com), то код виджета группы ВКонтакте будет вызван асинхронно, и прорисовка страницы не приостановится на моменте вызова скрипта ни на секунду.

Теперь заменим синхронный код рекламного блока Google Adsense на асинхронный. Сейчас он выглядит у нас как-то вот так, и тормозит загрузку страницы:

<script type="text/javascript">
google_ad_client = "ca-pub-...";
google_ad_slot = "...";
google_ad_width = x;
google_ad_height = y;
</script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">

Асинхронный код рекламного блока Google Adsense

Здесь я ничего придумывать не буду, а приведу пример кода из справочного раздела официального сайта Google:

<ins class="adsbygoogle"
style="display:block; width:728px; height:90px"
data-ad-client="ca-pub-..."
data-ad-slot="..."></ins>
<script>
( adsbygoogle = window.adsbygoogle || [] ).push( {} );
</script>

И ещё обязательно надо произвести асинхронную загрузку скрипта Google Adsense. На всякий случай, лучше в конце страницы (т.е. после самого последнего рекламного блока в коде страницы):

<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" async></script>

Если мне не верите или сомневаетесь (всё же, дело касается ваших денег), вот официальный источник — посмотрите там, заодно прочитайте ответы на часто задаваемые вопросы.

Итак, теперь вы сами можете сделать вызовы всех скриптов своего сайта асинхронными, и страница ваша со всем текстом будет отрисована браузером моментально, а не рисоваться блоками, пугая развалами вёрски.

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

Для разнообразия приведу пример вызова блока комментариев ВКонтакте с асинхронной загрузкой при помощи jQuery.

Асинхронный код комментариев ВКонтакте

комментарии ВКонтакте

Если вы ещё не используете на сайте комментарии ВКонтакте, вам сначала надо зарегистрировать сайт. Для регистрации сайта идём на эту страницу (требуется авторизация). И указываем необходимые параметры.

При этом вы получите синхронный код, который вам надо внимательно посмотреть, чтобы решить, какие настройки блока комментариев ВКонтакте будут для вас индивидуальны — вам надо будет их вписать в мой асинхронный код:

<div id="vk_comments"></div>
<script type="text/javascript">
( function( $j ) { $j( function() {
	$j.ajax( {
		url: 'vk.com/js/api/openapi.js',
		cache: true,
		dataType: 'script',
		success: function() {
			VK.init( { apiId: ваш_id, onlyWidgets: true } );
			VK.Widgets.Comments( "vk_comments", { limit: 4, width: "640", attach: "*" } );
		}
	} );
} ) } )( jQuery );
</script>

Как вы догадались, вместо ваш_id используется ваш id, а вместо limit: 4, width: "640", attach: "*" — ваши настройки. И ещё, если вы на одной странице используете и комментарии ВКонтакте, и виджет, то в последнем примере рядом с вызовом функции VK.Widgets.Comments добавьте и вызов VK.Widgets.Group.

Кстати, в jQuery есть функция getScript(), которую можно использовать вместо ajax()... Но не нужно. :) Несмотря на то, что функция getScript() предназначена специально для загрузки скриптов с их последующим выполнением (частный случай функции ajax()), она не кэширует загружаемые скрипты. Т.е. скрипт будет загружаться при каждой загрузке страницы. В моём же примере скрипт будет загружен только при первом запросе (возможно, этот скрипт уже загружен при посещении другого сайта с виджетом ВКонтакте) — на что потратятся секунды, а в дальшейшем будет браться из кэша браузера, для чего достаточно долей секунды.

На этом «продвинутые» веб-мастеры отправляются ковырять код своих сайтов, а не столь продвинутые с благоговением думают, сколько же в мире всего интересного и непостижимого! Но и тех, и других я жду в комментариях. ;) Напишите, вызов каких скриптов у вас осуществляется синхронно, а вы хотели бы сделать (или сделали) асинхронным.

Кстати, я тут как сапожник без запог, потому что на этом сайте у меня скрипты загружаются не асинхронно. :) Ведь в первую очередь на доработку отправляются приносящие доход сайты, а этот сайт у меня только время отнимает. Вот пример сайта, на котором все скрипты загружаются асинхронно, а именно: jquery, yandex metrika, yandex context, adsbygoogle, vk openapi, functions.js, share42 (социальные кнопки). Как это реализовано и как синхронизирована работа скриптов — без труда читается в исходном коде страницы и в файле functions.js.

Запись опубликована в рубрике Web-мастеринг с метками , . Короткая ссылка для добавления в закладки: Делаем все скрипты сайта асинхронными без дополнительных фреймворков.

37 Responses

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

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

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