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

Далеко не всегда эта проблема связана с качеством внешних ресурсов. Порой разработчики сайтов просто не успевают следить за новыми подходами, которые позволяют сделать интеграцию сторонних JavaScript модулей безопасной для производительности сайта.

Google Analytics
Уже давно по умолчанию Google рекомендует использовать асинхронный вариант загрузки трэкера:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
_gaq.push(['_trackPageview']);
(function() {
	var ga = document.createElement('script');
	ga.type = 'text/javascript';
	ga.async = true;
	ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
	var s = document.getElementsByTagName('script')[0];
	s.parentNode.insertBefore(ga, s);
})();

В то же время, согласно проведенному исследованию, среди 500 самых популярных сайтов в России каждый второй сайт использует систему аналитики Google Analytics, при этом каждый третий из них по-прежнему придерживается традиционного варианта с конструкцией document.write.

В число подобных сайтов входят даже такие популярные ресурсы как bash.org.ru, livejournal.ru и auto.ru.

Но и рекомендуемый по умолчанию вариант не является оптимальным. Так, если на странице используется только один трэкер кода, то конструкцию

var _gaq = _gaq || [];

можно смело заменить на

var _gaq = [];

Многократное использование метода push также необязательно, и код можно сократить до:

_gaq.push(['_setAccount', 'UA-XXXXX-X'], ['_trackPageview']);

Свойство type является избыточным

ga.type = 'text/javascript';

Большинство браузеров (включая IE 6) и без того по умолчанию присваивают значение text/javascript данному атрибуту.

Разумеется, во многих случаях можно опустить проверку используемого протокола:

ga.src = 'http://www.google-analytics.com/ga.js';

Это не только сокращает размер кода, но и время его выполнения.

В конечном итоге, применив общие рекомендации по оптимизации кода JavaScript, можно прийти к следующей реализации:

<script type="text/javascript">
	var _gaq = [['_setAccount', 'UA-XXXXX-X'], ['_trackPageview']];
	(function(d, t) {
		var ga = d.createElement(t),
		     s = d.getElementsByTagName(t)[0];
		ga.async = 1;
		ga.src = 'http://www.google-analytics.com/ga.js';
		s.parentNode.insertBefore(ga, s);
	})(document, 'script');
</script>

Google +1
Ошибка в типе протокола, рекомендация о включении скрипта в заголовок HTML документа, срок кэширования всего 6 минут, неминимизированный JavaSript код, синхронная загрузка.

С этим столкнулись первые пользователи данного виджета. Спустя два месяца после релиза специалисты Google обновили реализацию плагина, но на многих страницах осталась самая первая версия.

Теперь код выглядит следующим образом:

(function() {
	var po = document.createElement('script');
	po.type = 'text/javascript';
	po.async = true;
	po.src = 'https://apis.google.com/js/plusone.js';
	var s = document.getElementsByTagName('script')[0];
	s.parentNode.insertBefore(po, s);
})();

Очевидно, что и к нему применимы некоторые из техник, которые были описаны в предыдущем разделе.

Плагины Facebook
На сегодняшний день плагины социальной сети Facebook можно интегрировать посредством трех основных механизмов: HTML5, iframe и XFBML. Именно последний вариант является оптимальным с точки зрения кросс-браузерной поддержки, а также с точки зрения производительности.

К сожалению, даже при использовании XFBML далеко не все загружают JavaScript SDK асинхронно. Более того, иногда приходится сталкиваться с ситуациями, когда для создания различных плагинов разработчики сайтов используются различные методы загрузки. Отсутствие единого подхода в итоге приводит к загрузке избыточных ресурсов и потерям в скорости сайта.

Например, при реализации кнопки «Like» с использованием XFBML требуемая библиотека подгружается с помощью следующего кода:

(function(d, s, id) {
	var js, fjs = d.getElementsByTagName(s)[0];
	if (d.getElementById(id)) return;
	js = d.createElement(s); js.id = id;
	js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
	fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

Отсутствие атрибута async не критично, лишь браузер Firefox 3.6 требует явного указания

js.async = 1;

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

Оптимизировать же можно непосредственно выполняемый код. Все функции или по-крайней мере их инициализация должны осуществляться внутри специальной функции window.fbAsyncInit, например:

window.fbAsyncInit = function() {
    FB.init({
      appId      : 'YOUR_APP_ID',
      channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html',
      status     : true,
      cookie     : true,
      xfbml      : true
    });
  };

Именно такой вариант реализации в данный момент является оптимальным и описывается в официальной документации. Если указывается файл channel.html, то важно не забыть о том, чтобы сервер возвращал его с максимальными сроком кэширования в HTTP заголовке.

Универсальный шаблон и загрузчики JavaScript
Как видно из представленных примеров, процесс загрузки внешних ресурсов во всех случаях выглядит практически одинаково. Поэтому скорее приходится говорить о шаблоне, который можно использовать и для других источников, будь то Twitter или LinkedIn. Меняются лишь ссылки и id объектов.

Можно ли сделать его лучше? Безусловно. Немедленно вызываемую функцию в отдельных случаях можно можно разнообразить привязкой к onload событию браузера. Например, загрузка Facebook JavaScript SDK может выглядеть так:

(function(d, s, id) {
	function delayedLoad() {
		var js, fjs = d.getElementsByTagName(s)[0];
		if (d.getElementById(id)) return;
		js = d.createElement(s); js.id = id;
		js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
		fjs.parentNode.insertBefore(js, fjs);
	}

	if (window.addEventListener) {
		window.addEventListener("load", delayedLoad, false);
	} else if (window.attachEvent) {
		window.attachEvent("onload",delayedLoad);
	}
}(document, 'script', 'facebook-jssdk'));

Несмотря на то, что размер кода заметно увеличился, загрузка модуля наверняка произойдет после загрузки основных объектов страницы.

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

Мы уже рассказывали о возможностях LabJS. К числу популярных альтернатив также относятся HeadJS и ControlJS. С их помощью процесс загрузки и выполнения легко сделать полностью асинхронным, контролируемым и, в конечном итоге, быстрым.

Источники:

Метки: