Загрузка JavaScript(без блокировки отрисовки документа, асинхронная загрузка)

/
2014-10-12 00:41
Просмотры: 19716

С ростом скорости интернет соединения и увеличении мощности не только десктопных, но и мобильных устройств веб страницы стают более "тяжелыми". Количество и размер подключаемых файлов растет: JavaScript файлы, css файлы, изображения, виджеты сторонних сайтов, iframe. На данный момент специфика работы браузеров такая, что при загрузке js файла блокируется отривсовка до того момента, пока скрипт не выполниться. Современные браузеры в фоновом режиме будут парсить документ и скачивать скрипты и стили, но отрисовка будет заблокирована. Сравнение сетевых параметров для различных браузеров можно посмотреть на browserscope.org. Мы не можем устранить блокировку полностью, но можем оптимизировать серверную и клиентскую часть приложения, что бы блокировка отрисовки занимала наименьший промежуток времени.

Решения для серверной части:
- Уменьшить размер передаваемых файлов
- Использовать CDN
- Вынести статические файлы на отдельный домен или под домен, таким образом увеличить количество одновременных соединений браузера.
- Включить сжатие передаваемых файлов(gzip)

Решения для клиентской части:
- Уменьшить количество запросов.
- Кэшировать файлы на стороне клиента с помощью заголовков Expires и Etags.
- Использовать общедоступные CDN(Google CDN, Yandex CDN). Таким образом, существует вероятность, что файл с общедоступного CDN уже будет храниться в кеше браузера.
- Асинхронная загрузка подключаемых файлов.

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

Скрипт асинхронной загрузки JavaScript:

<script type="text/javascript">
(function() {
    var s = document.createElement('script');
    s.type = 'text/javascript';
    s.async = true;
    s.src = 'URL файла';
    document.getElementsByTagName('head')[0].appendChild(script);
})();
</script>

Если JavaScript нужно выполнить после загрузки всей страницы, включая содержание, изображения, стилевые файлы и внешние скрипты, то к загрузчику нужно добавить отслеживания события onload.

 
if (window.addEventListener) {
    window.addEventListener('load', async_load, false);
} else if (window.attachEvent) {
    window.attachEvent('onload', async_load);
}

Скрипт асинхронной загрузки JavaScript с учетом события onload

<script type="text/javascript">
(function() {
	function async_load(){
	    var s = document.createElement('script');
	    s.type = 'text/javascript';
	    s.async = true;
	    s.src = 'URL файла';
	    document.getElementsByTagName('head')[0].appendChild(script);
	}

	if (window.addEventListener) {
	    window.addEventListener('load', async_load, false);
	} else if (window.attachEvent) {
	    window.attachEvent('onload', async_load);
	}
})();
</script>

Но это единичный случай, когда требуется загрузка одного файла. Часто на практике подключается множество файлов.

Скрипт асинхронной загрузки множества подключаемых JavaScript файлов

<script type="text/javascript">
(function() {
	function async_load(){
		[
			'URL_файла_1.js',
			'URL_файла_2.js',
			'URL_файла_3.js'
		].forEach(function(src) {
			var s = document.createElement('script');
			s.type = 'text/javascript';
			s.async = true;
			s.src = src;
			document.getElementsByTagName('head')[0].appendChild(script);
		});
	}

	if (window.addEventListener) {
	    window.addEventListener('load', async_load, false);
	} else if (window.attachEvent) {
	    window.attachEvent('onload', async_load);
	}
})();
</script>

Но в такой реализации есть минус - скрипты будут загружаться в произвольном порядке и соответсвенно выполнятся они будут произвольно во времени. Данный скрипт асинхронной загрузки идеально подходит, если выполнение JavaScript файлов не зависят один от другого и не зависит от DOM. В обратном случае его использование может привести к ошибкам на странице или непредвиденному результату выполнения. Для последовательного выполнения, но асинхронной загрузки, нужно указать async=false, тогда файлы будут скачиваться в произвольном порядке, но выполняться по очереди.

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

Стандарт HTML 5 поддерживает асинхронную загрузку JavaScript. Это можно сделать путем добавления ключевого слова async или defer. Например:

<script src="URL_скрипта" type="text/javascript" async></script>
<script src="URL_скрипта" type="text/javascript" defer></script>

В обеих вариантах загрузка javascript будет асинхронной. Разница состоит только в начале времени выполнения скрипта.

Скрипт, который подключен с атрибутом defer выполнится не нарушая порядок выполнения по отношению к остальным скриптам и его выполнение произойдет после полной загрузки и парсинга страницы, но перед тем, как вызовется DOMContentLoaded.

Скрипт, который подключен с атрибутом async выполнится при первой возможности после полной загрузки, но при этом не ожидает окончания парсинга документа и до загрузки объекта window. Браузеры не гарантируют выполнение скриптов в том же порядке в котором они подключены.

Библиотеки для асинхронной загрузки JavaScript

RequireJS - модуль загрузки JavaScript. Оптимизирован под браузеры, но он может использоваться в других средах, таких как Node, Rhino.

require(["script"], function(script) {
	console.log("start after load script.js");
});

extsrc.js — библиотека, которая запускает скрипты на выполнение после того, как страница загрузится и отобразится пользователю. Работает корректно с document.write.

<script src="http://extsrcjs.googlecode.com/svn/trunk/extsrc.js"></script>
<script extsrc="...."></script>
<script asyncsrc="...."></script>

yepnope.js - позволяет совершать асинхронную загрузку JavaScript и CSS файлов.

yepnope([
	'script.js',
	'style.css'
]);

Простой способ загрузки JavaScript скриптов

Оказывается, что на практике добиться оптимальной кросс браузерной загрузки JavaScript скриптов, которые не блокируют отображение сложно, а порой невозможно. Наиболее оптимальный способом является добавление <script type="text/javascript" src="souuce_script.js"></script> в конец документа перед закрывающимся тегом body. Из за ограничения разных браузеров и самого HTML такой вариант загрузки, который не блокирует отображение, можно считать наиболее простой.

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

comments powered by Disqus