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

Поводом к написанию этого поста послужило то, что не раз мне приходилось замечать, что вставка на страницу кода кнопок различных сервисов (например: вконтакте, фейсбук, твиттер, одноклассники) приводила к заметному замедлению загрузки и отображения страницы. Речь идет о том случае, когда используется подключение внешних javascript этих социальный сервисов.
Если мы используем простые статичные графические кнопки, никаких проблем нет, т.к. это минимум графики и скриптов, которые расположены локально (можно посмотреть пример реализации тут http://pervushin.com/social-button-for-blog.html). Но мы видим только иконки соц. сервисов, никакой статистики (сколько нашу страницу "залайкнули") нет. Т.е. если мы хотим видеть и статистику, то придется подключать внешние скрипты. И тут стоит иметь в виду, что сколько таких кнопок мы подключили, то столько внешних скриптов браузер вынужден скачать, т.е. это дополнительные подключения к внешним серверам.

Чтобы показать, что происходит, если на странице есть скрипты в секции , предлагаю рассмотреть ряд тестовых примеров. Я буду использовать FireFox 3.6 и FireBug.

Итак:
1) Простейшая страница с одним файлом стилей, двумя скриптами и тремя картинками:













А вот диаграмма загрузки для нее:

Обратите внимание, что все картинки грузятся только после загрузки самого "долгого" javascript файла.
Я намеренно сделал довольно длительной загрузку dummy_css.css и dummy_js.js. Это просто два файла:

dummy_css.php

html, body {
margin:0;
padding:0;
}
.img_container{
margin:0 auto;width:500px;
}

dummy_js.php


var param=1;

Итак, видно что js файл блокирует загрузку всей остальной графики.

2) Все почти то же самое, но dummy_ js. js грузится с внешнего хоста:

Ситуация аналогична предыдущей:

3) Попробуем поменять в секции head местами css и js файлы (css теперь идет после js):







Смотрим на диаграмму загрузки:

Js по-прежнему блокирует загрузку картинок, независимо от того, с какого хоста он грузится.

4) Увеличим по времени загрузку css до 4-х секунд (html код как в случае N3):

5) Еще один интересный случай: css располагается до js, но css грузится дольше















Тут уже css блокирует загрузку картинок...

6) Переносим один js внутрь < body>
















Видно, что dummy_ js. js блокирует загрузку только третьей картинки, которая расположена в html коде после него. Но если css грузится дольше, то тогда уже он будет блокировать загрузку графики. Нетрудно представить, что подключаемые внешние скрипты могут сильно замедлить загрузку и отрисовку страницы, особенно если удаленный сервер по каким-то причинам долго отвечает.

Размещение внешних скриптов перед

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

Но есть еще одна проблема, поясню на примере:




$("img").click(function() {
alert($(this).attr("src"));
});
});






Если js перед будет грузиться долго, то клики по картинкам до полной загрузки этого скрипта ни к чему не приведут, т.к. $(document).ready() сработает только после полной загрузки js. Так что если на страницах есть некая логика, которая предусматривает обработку событий, то этот способ мало подходит.

Итак, что нужен способ неблокирующей загрузки скриптов...

Создаем async.js:



script.src = "dummy_js.js";


и подключим его:











$(document).ready(function() {
$("img").click(function() {
alert($(this).attr("src"));
});
});






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

Но если в коде все-таки удобнее размещать async.js именно в , то следует немного поменять содержимое async.js:

$(document).ready(function() {
var script = document.createElement("script");
script.src = "dummy_js.js";
document.getElementsByTagName("head") .appendChild(script);
}
);

Итак, вопрос асинхронной загрузки решен, но остается открытым вопрос синхронизации загрузки внешних скриптов и кода, их использующих. Рассмотрим его на практике, подключая кнопки социальных сетей.

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

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

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

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

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

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

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

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

Скрипт асинхронной загрузки JavaScript с учетом события onload (function() { function async_load(){ var s = document.createElement("script"); s.type = "text/javascript"; s.async = true; s.src = "URL файла"; document.getElementsByTagName("head").appendChild(script); } if (window.addEventListener) { window.addEventListener("load", async_load, false); } else if (window.attachEvent) { window.attachEvent("onload", async_load); } })();

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

Скрипт асинхронной загрузки множества подключаемых 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").appendChild(script); }); } if (window.addEventListener) { window.addEventListener("load", async_load, false); } else if (window.attachEvent) { window.attachEvent("onload", async_load); } })();

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

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

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

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

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

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

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

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

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

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

Yepnope([ "script.js", "style.css" ]);

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

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

Асинхронность в javascript — представляет собой правило в соответствии с которым блоки JS кода обрабатываются браузером параллельно с загрузкой DOM — т.е. структуры веб-страницы или после загрузки DOM.

Код на JS, как известно, помещается между тегами . При этом код может содержаться как в HEAD документа, так и в BODY — при этом в любой части документа. Также javascript можно подгружать с других доменов.

Обычно JS помещают в конце страницы именно из тех соображений, что на обработку кода уходит определенное время — загрузка страницы при этом приостанавливается — DOM не может загрузиться поскольку ждет завершения исполнения скритпа на javascript.

Если при этом скрипт написан с ошибками или подгружается с внешнего сервера, который оказался недоступен — страница не загрузится никогда. Если JS код просто плохо оптимизирован и выполняется долго — страница загрузится до того места в котором подключается скрипт — затем загрузка остановится до того момента пока выполнение скрипта не завершится . Это может быть замечено посетителем сайта, особенно если он использует медленное соединение с Интернетом.

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

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

Скрипт инициируется, страница продолжит загружаться даже если скрипт не завершил свою работу. Какой-то функционал страницы при этом может работать некорректно (если в javascript допущены ошибки) — в целом же страница загружается и посетитель сайта может с ней работать.

Стоит отметить, что async не поддерживается некоторыми версиями Internet Explorer, но поскольку пользуется им очень маленькое количество пользователей — обычно имеет смысл этим пренебречь и использовать асинхронность в javascript.

Альтернативой async может быть defer . При использовании данного атрибута скрипт будет исполняться только после того как загружен DOM. Директива поддерживается всеми браузерами, ее особенность в том, что она обрабатывает JS скрипты в том порядке, в котором они подключаются.

Это может быть как плюсом, так и минусом. Если порядок выполнения скриптов принципиален — defer — лучшее решение.async можно принудительно отключить: script.async=false;

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

Иногда возникает необходимость в поэтапной асинхронной загрузке данных. И это может быть все, что угодно. Начиная от загрузки зависимых справочников (например, страна -> города), заканчивая объединением и обработкой информации с различных источников (например, вы используете несколько разных сервисов, и каждый из них тратит разное время на формирование данных).

А теперь чуть попроще.

Проблематика поэтапной асинхронной загрузки данных в jQuery (ajax)

Если вам надо связать несколько последовательно выполняемых ajax-запросов в jQuery, то самым простым решением будет - сделать вызов следующей функции в конце каждого обработчика success. Это не только достаточно просто, но и не вызывает никаких проблем. Например,

// Первый запрос $.ajax(url, { ... success: function (result) { // Какой то код... // Вызов следующего обработчика nextLoader(); } });

А теперь, допустим, перед вами стоит чуть более сложная задача. Например, вам необходимо запустить функцию только после того, как выполнятся несколько асинхронных запросов (например, получение пузомерок для сайта). Конечно, их так же можно связать в прямую цепочку, как это было показано выше. Но, при этом начинает теряться сама суть асинхронности. И так же может получиться, что вы строите зависимость между совершенно не связанными блоками. Согласитесь, что показатель тИЦ и данные по whois не совсем зависят друг от друга.

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

Но, что вы будете делать, если ваша задаче окажется еще сложнее? Когда вам необходимо все операции и загрузки данных распределить по этапам. Например, вы составляете формочку диалога. На первом этапе будет идти получение данных для всех полей (выпадающие списки, группы чекбоксов и т.д.). На втором этапе будет происходить определение обработчиков для созданных полей. А на третьем этапе, уже после полной загрузки "всё и вся", открывать доступ к различным кнопкам и другим элементам интерфейса (чтобы шаловливые ручки не создали вам кучи проблем). Чисто визуально это может выглядеть так:

Согласитесь, что организовать вызов всех функций в одну цепочку - ни только не простое занятие, но еще и не очень приятное. Кроме этого еще представьте, что вам надо добавить несколько полей и различных обработчиков. Что будет? У вас начнет голова закипать от поиска нужных мест "куда вставить". Тут уже нужен какой-то механизм, который позволит вам выстроить все запуски поэтапно.

Пишем скрипт для организации поэтапной асинхронной загрузки в jQuery

Первым делом необходимо определиться с вполне логичным вопросом "почему не использовать готовые библиотеки?". Как такового, ответа на этот вопрос не существует. Все очень сильно зависит от задачи. Так как слово "библиотека" обычно подразумевает:

  • отсутствие управляемости кода (вы не можете поменять внутреннюю логику библиотеки; а если вы это сделаете, то любое изменение может сильно "аукнуться" в будущем)
  • необходимость изучения ее базовый свойств и принципов (обычно, это сводится к прочтению всей возможной документации и куче различных тестов)
  • ограничения на версии jQuery (если используются сложные ядровые механизмы, то возможно привязка к версии библиотек jQuery)
  • возможные проблемы совместимости с другими скриптами (далеко не факт, что библиотека будет корректно себя вести с другими библиотеками)
  • чрезмерное богатство функциональности, и как следствие наличие "дополнительных ограничений"
  • и т.д.

Примечание : Не стоит входить в заблуждение, ведь у библиотек есть огромное количество плюсов. Если вспомнить, то и jQuery - это то же библиотека. В статье акцент фокусируется на рисках и дополнительных затратах времени, которые от вас могут потребоваться.

Именно, поэтому необходимо сначала определиться с вашими задачами (количество, частота возникновения), со временем (сколько вы готовы потратить на решение задачи), чем вы готовы пожертвовать (важна ли для вас возможность быстро что-то подправить; важен ли размер библиотек; насколько ограничения вас устраивают), предпочтениями (например, вы принципиально не используете библиотеки). И уже только после того, как вы ответите себе на эти вопросы, пытаться ответить на вопрос "почему стоит или не стоит использовать готовые библиотеки?".

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

Если же вы полны энтузиазма и решимости, то преступим к дальнейшим действиям.

Составляем требования к скрипту

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

  • Подключение и настройка скрипта должны происходить автоматически (вам необходимо подключить лишь файл js)
  • Повторное подключение файла скрипта не должно вызывать сбой
  • Использовать только стандартные механизмы jQuery
  • Интерфейс должен быть простым и понятным
  • Вы можете составлять несколько независимых цепочек этапов
  • У вас всегда должна быть возможность быстро подкорректировать действия скрипта
  • Скрипт не должен накладывать сложные ограничения на ваш код (максимально - необходимость в добавлении функции оповещения о своем выполнении)

Примечание : Всегда формируйте требования так, чтобы при реализации не начать заниматься тем, что вообще не требуется. И обязательно включайте в него "итак понятные" пункты, чтобы эти пункты и дальше оставались "итак понятными".

Составляем тестовый проект

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

  • css - каталог со стилями
    • template.css - стили тестового проекта
  • images - каталог с картинками (для визуального эффекта)
    • ajax-loader.gif - картинка загрузки
  • js - каталог со скриптами
    • jquery-ajax-stage.js - скрипт для поэтапной загрузки
  • data.json - тестовые данные
  • index.html - начальная страница

Примечание : При составлении структуры тестового проекта, старайтесь максимально приблизить ее к структуре настоящего проекта. Это поможет вам отловить проблемы, связанные со структурой, еще на этапе разработке.

Файл с тестовыми данными - data.json

Этот файл нужен только для того, чтобы можно было убедиться, что загрузка данных через ajax никак не повлияет. Вы можете наполнить его любым json. Например, так:

{ data: "Много данных" }

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

Файл стилей - template.css

Этот файл нужен только затем, чтобы вынести все стили отдельно. Так как к самой разработке скрипта стили не имеют никакого отношения. Да, и просто это считается хорошей практикой. Сами стили:

Left-table { float: left; padding-right: 10px; } .right-table { float: left; padding-right: 10px; } table.table-loader { border-spacing: 0px; border-collapse: collapse; width: 300px; } table.table-loader tr td { padding: 5px; border: 1px solid #ccc; }

Файл скрипта для поэтапной асинхронной загрузки - jquery-ajax-stage.js

Сама реализация поэтапной асинхронной загрузки.

(function (parentObject) { // Защита от повторного определения if(parentObject.eventManager) return; // Определяем объект parentObject.eventManager = { // Добавляем этап addStage: function (el, stageName) { var elCount = $(el).length; // Проверяем корректность параметров if(elCount > 0 && !!stageName) { // Такой этап уже есть if (($(el).get(0).eventStages = $(el).get(0).eventStages || {})) return; // Определяем "nfg $(el).get(0).eventStages = { waiterCount: 0, // Счетчик объектов находящихся в состоянии ожидания данных onEvent: // в данном массиве будут хранится все функции для вызова }; } }, // Удаляем этап removeStage: function (el, stageName) { var elCount = $(el).length; // Проверяем корректность параметров if(elCount > 0 && !!stageName) { // Такой этап нашелся if (($(el).get(0).eventStages = $(el).get(0).eventStages || {})) { delete ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); ($(el).get(0).eventStages = $(el).get(0).eventStages || {}) = null; } } }, // Увеличиваем счетчик выполняемых функций для этапа addStageWaiter: function (el, stageName) { var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); // Проверяем корректность параметров if(elCount > 0 && !!stageName && stage) { // Увеличиваем счетчик загрузок stage.waiterCount++; } }, // Уменьшаем счетчик выполняемых функций для этапа // Т.е. оповещаем, что функция выполнилась removeStageWaiter: function (el, stageName) { var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); // Проверяем корректность параметров if(elCount > 0 && !!stageName && stage) { // Уменьшаем счетчик загрузок stage.waiterCount--; // Проверяем состояние этапа this.checkStage(el, stageName); } }, // Проверяем состояние этапа checkStage: function (el, stageName) { var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); // Проверяем корректность параметров if(elCount > 0 && !!stageName && stage) { if (stage.waiterCount 0) { // Очередь FIFO - первый вошел, первым вышел, как в магазине stage.onEvent.shift()(); } } } }, // Добавляем вызов функции, который запустится при выполнении всего этапа onLoadStage: function (el, stageName, funcHandler) { var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); // Проверяем корректность параметров if(elCount > 0 && !!stageName && stage && typeof (funcHandler) === "function") { // Добавляем обработчик stage.onEvent.push(funcHandler); // Проверяем состояние этапа this.checkStage(el, stageName); } } }; })(window);

Тестовая страница - index.html

Тестовая страница получилась достаточно большой (порядка 160 строк), поэтому будет приведена только часть кода. Полную версию файла вы всегда можете найти в zip-архиве.

Подключаем все необходимые файлы:

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

Начать загрузку

Определим функцию, которая будет создавать тестовые функции для этапов:

function getFakeLoader(storage, currStage, startDate, selector) { return function () { setTimeout(function () { $.ajax("data.json?callback=?", { contentType: "text/plain; charset=utf-8", dataType: "jsonp", jsonpCallback: function (result) { $(selector).html("Время от начала: " + ((+new Date() - startDate)/1000.0).toFixed(2) + " секунд"); // Пишем время загрузки window.eventManager.removeStageWaiter(storage, currStage); // Уменьшаем счетчик } }); }, Math.random() * (3000) + 1000 // Задежрка от 1 до 4 секунд); }; }

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

function formTestFor(selector) { $(selector + " .start-process").click(function () { var startDate = new Date(); // Для красоты добавим картинки setLoaderImgs(selector); // Определим этапы window.eventManager.addStage($(selector + " .table-loader"), "1"); window.eventManager.addStage($(selector + " .table-loader"), "2"); window.eventManager.addStage($(selector + " .table-loader"), "3"); // Заблокируем кнопку до конца этапа $(selector + " .start-process").attr("disabled", "disabled"); // Наполним очередь ожидания по 3 загрузки на стейдж // По факту эти действия должны происходить в местах запуска функций этапов window.eventManager.addStageWaiter($(selector + " .table-loader"), "1"); ... window.eventManager.addStageWaiter($(selector + " .table-loader"), "3"); // Теперь создадим в обратном порядке (для наглядности) функции загрузки // По факту эти действия должны происходить в местах определения функций window.eventManager.onLoadStage($(selector + " .table-loader"), "2", getFakeLoader($(selector + " .table-loader"), "3", startDate, selector + " .row-3 .td-1")); ... window.eventManager.onLoadStage($(selector + " .table-loader"), "1", getFakeLoader($(selector + " .table-loader"), "2", startDate, selector + " .row-2 .td-3")); // Добавим обычный текстовый вывод готовых этапов window.eventManager.onLoadStage($(selector + " .table-loader"), "1", function () { $(selector + " .row-1-end td").html("Первый этап закочнился за " + ((+new Date() - startDate)/1000.0).toFixed(2) + " секунд. Начинается следующий этап."); }); ... window.eventManager.onLoadStage($(selector + " .table-loader"), "3", function () { $(selector + " .row-3-end td").html("Третий этап закочнился за " + ((+new Date() - startDate)/1000.0).toFixed(2) + " секунд.
Загрузка окончена"); }); // После окончания третьего этапа разблокируем кнопку onLoadStage window.eventManager.onLoadStage($(selector + " .table-loader"), "3", function () { // Разблокируем кнопку $(selector + " .start-process").attr("disabled", null); }); // Теперь запустим функции первого этапа getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-1")(); getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-2")(); getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-3")(); // Наблюдаем... }); }

Теперь собираем все файлы в проект и переходим к первичному тестированию и демонстрации.

Смотрим результат

Открываем файл index.html в браузере. Должен отобразиться следующий интерфейс:

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

После того, как оба процесса закончили свое выполнение, смотрим на время и убеждаемся, что этапы происходили в нужном порядке:

Закончив первичное тестирование, переходим к проверке требований:

  • Подключение и настройка скрипта должны происходить автоматически (вам необходимо подключить лишь файл js) - Есть
  • Повторное подключение файла скрипта не должно вызывать сбой - Есть
  • Использовать только стандартные механизмы jQuery - Есть (использовался только функционал селекторов)
  • Интерфейс должен быть простым и понятным - Есть
  • Вы можете составлять несколько независимых цепочек этапов - Есть
  • У вас всегда должна быть возможность быстро подкорректировать действия скрипта - Есть (скрипт составлен достаточно просто; основную часть составляют проверки входных данных)
  • Скрипт не должен накладывать сложные ограничения на ваш код (максимально - необходимость в добавлении функции оповещения о своем выполнении) - Есть (внутри функций getFakeLoader вызывается только функция для оповещения о своем завершении)

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

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

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

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

Когда браузер считывает html-код, он отображает результат последовательно. Т.е. каждая строка идет друг за другом, но в месте, где установлен javascript происходит остановка – с этой проблемой приходилось, безусловно, сталкивались те, кто использует этот язык для написания ресурсов.

Решение проблемы - асинхронная загрузка. Просто разместите javascript в конце html-кода страницы. Это приведет к тому, что загрузка «явы» будет отдалена по времени, обеспечивая корректное отображение страницы и быстрый страт для пользователей ресурса. На асинхронную загрузку переходят большинство серьезных ресурсов, старающихся сохранить аудиторию и внедрить полезное нововведение.

Разберем несколько способов оптимизации загрузки javascript.

Такая загрука javascript-файла осуществляется следующим образом:

< script src= type= "text/javascript" >

HTML5 предусмотрительно озаботился проблемой загрузки страницы с «явой». В нем есть возможность установить асинхронную загрузку скрипта, что увеличивает скорость отображения ресурса в разы. Для этого в html-код следует добавить параметры async или defer , как это указано ниже:

< script async src= "//www.адрес_сайта/script.js" type= "text/javascript" >

< script defer src= "//www.адрес_сайта/script.js" type= "text/javascript" >

В чем разница между атрибутами async и defer?

Оба параметра работают с асинхронной загрузкой javascript. Различие состоит во времени отображения и начале выполнения работы скрипта.

Атрибут async запустит скрипт сразу же, после полной загрузки, но при этом пропустит загрузку window.

При установке в код страницы атрибута defer - javascript встанет в очередь между другими скриптами, не нарушая их порядок выполнения. Он начнет работу только после полной загрузки страницы, но пропустит событие DOMContentLoaded (объект document).

Однако, данные атрибуты не работают в некоторых современных браузерах. Так, например, InternetExplorer не поддерживает атрибуты async и defer. А строки document.write ничем не помогут в файлах script.js

Специальный скрипт от Google для асинхронной загрузки javascript

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

Чтобы применить данный скрипт, просто заменяем

на

Затем подключаем файл скрипта extsrc.js

Получаем следующий код:

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

К сожалению, этот способ тоже не подойдет к файлам с document.write

Этот способ подойдет для всех браузеров без исключения и работает даже с document.write

В html-коде страницы создаем пустой div-блок:

А в конце html-кода, перед , вставляем скрипт для асинхронной загрузки:

Здесь любой файл или скрипт, который нужно загрузить. // переместить его в реальную позицию отображения document.getElementById("script_block").appendChild(document.getElementById("script_ad")); // показать document.getElementById("script_ad").style.display = "block";

Обратите внимание, что в версиях IE ниже 6-ой, включительно, такая загрузка не работает. Но я не уверен, что такие пользователи остались - их меньшинство. Другие браузеры и сервисы используют данную оптимизацию для javascript, что отражается лучшим образом на скорости загрузки ресурсов.