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

Приветствую, друзья! Знаете ли Вы, что загрузка JavaScript является одним из самых узких мест в производительности сайта? Сегодня моя основная задача — объяснить что такое скрипта и каким образом она влияет на быстродействие и производительность сайта.

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

  • конфигурации ,
  • скорости интернет-соединения,
  • размера файла и других…

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

Если код скрипта влияет на отображение верхней части сайта — не выносите его в отдельный файл, а встраивайте непосредственно в HTML.

JS может изменить содержимое сайта и даже перенаправить на другой URL-адрес. В таком случае подключение скрипта в конце документа приведет к эффекту «подергивания» страницы, подгружая новые или изменяя существующие элементы в верхней части.

Применение атрибутов async и defer для тега script

Давайте разберемся, что из себя представляет асинхронная и отложенная работа JavaScript и какая принципиальная разница между атрибутами async и defer. Но вначале рассмотрим последовательность обработки документа при обычном подключении тега script .

1 < src = "example.js" >

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

— обработка страницы
— загрузка скрипта
— выполнение скрипта

Таким образом последовательность обработки происходит по следующей схеме:

Разбор HTML-кода прерывается на время загрузки и выполнения скрипта, после чего продолжается. Отображение веб-страницы происходит с задержкой.

Атрибут defer

Атрибут defer позволяет браузеру начать загрузку js-файлов параллельно, не останавливая дальнейшую обработку страницы. Их выполнение происходит после полного разбора объектной модель документа (от англ. Document Object Model, сокращенно DOM), при этом браузер гарантирует последовательность на основе порядка подключения файлов.

1 < defer src = "example.js" >

Атрибут async

Поддержка атрибута async появилась в HTML5, он разрешает браузеру загружать js-файлы параллельно и выполнять сразу после загрузки, не дожидаясь обработки остальной части страницы.

1 < async src = "example.js" >

Схема последовательности обработки:

Это асинхронная загрузка. Атрибут рекомендуется применять для таких скриптов, которые не оказывают значительного влияния на отображение документа. К ним относятся счетчики сбора статистики (Google Analytics, Яндекс Метрика), коды рекламных сетей (Рекламная сеть Яндекса, Google AdSense), кнопки социальных сетей и так далее.

Скорость загрузки сайта — один из факторов ранжирования в Google.

Асинхронное подключение JavaScript снижает время загрузки страниц за счет отсутствия задержки. Наряду с этим я рекомендую сжимать и объединять js-файлы в один, например, с помощью библиотеки . Пользователям нравятся быстрые сайты 😎

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

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

Проблематика поэтапной асинхронной загрузки данных в 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 вызывается только функция для оповещения о своем завершении)

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

) я писала о том, какой эффект оказывают JavaScript-файлы на Критический Путь Рендеринга(CRP).


JavaScript является блокирующим ресурсом для парсера. Это означает, что JavaScript блокирует разбор самого HTML-документа. Когда парсер доходит до тега <script> (не важно внутренний он или внешний), он останавливается, забирает файл (если он внешний) и запускает его.

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


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

Нормальное выполнение

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


... ... ....

Вот что произойдёт, когда парсер будет обрабатывать документ:

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

Атрибут async

Async используется для того, чтобы указать браузеру, что скрипт может быть выполнен асинхронно.
Парсеру HTML нет необходимости останавливаться, когда он достигает тега для загрузки и выполнении. Выполнение может произойти после того, как скрипт будет получен параллельно с разбором документа.



Атрибут доступен только для файлов, подключающихся внешне. Если внешний файл имеет этот атрибут, то он может быть загружен в то время как HTML-документ ещё парсится. Парсер будет приостановлен для выполнения скрипта, как только файл скрипта будет загружен.



Атрибут defer

Атрибут defer указывает браузеру, что скрипт должен быть выполнен после того, как HTML-документ будет полностью разобран.



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



Асинхронное, отложенное или нормальное выполнение?

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

Где расположен элемент ?

Асинхронное и отложенное выполнения наиболее важны, когда элемент не находится в самом конце документа. HTML-документы парсятся по порядку, с открытия до его закрытия. Если внешний JavaScript-файл размещается непосредственно перед закрывающим тегом , то использование async и defer становится менее уместным, так как парсер к тому времени уже разберёт большую часть документа, и JavaScript-файлы уже не будут оказывать воздействие на него.

Скрипт самодостаточен?

Для файлов, которые не зависят от других файлов и/или не имеют никаких зависимостей, атрибут async будет наиболее полезен. Поскольку нам не важно, когда файл будет исполнен, асинхронная загрузка - наиболее подходящий вариант.

Полагается ли скрипт на полностью разобранный DOM?

Во многих случаях файл скрипта содержит функции, взаимодействующие с DOM. Или, возможно, существует зависимость от другого файла на странице. В таких случаях DOM должен быть полностью разобран, прежде чем скрипт будет выполнен. Как правило, такой файл помещается в низ страницы, чтобы убедиться, что для его работы всё было разобрано. Однако, в ситуации, когда по каким-либо причинам файл должен быть размещён в другом месте - атрибут defer может быть полезен.

Скрипт небольшой и зависим?

Наконец, если скрипт является относительно небольшим и/или зависит от других файлов, то, возможно, стоит определить его инлайново. Несмотря на то, что встроенный код блокирует разбор HTML-документа, он не должен сильно помешать, если его размер небольшой. Кроме того, если он зависит от других файлов, может понадобиться незначительная блокировка.

Поддержка и современные браузерные движки

Поддержка атрибутов async и defer очень распространена:




Стоит отметить, что поведение этих атрибутов может немного отличаться в разных движках JavaScript. Например, в V8 (используется в Chromium), сделана попытка разобрать все скрипты, независимо от их атрибутов, на отдельном выделенном потоке для выполнения скрипта. Таким образом, «блокирующая парсер» природа JavaScript-файлов должна быть минимизирована по умолчанию.

Выход есть: поместить явавские строки в конец html документа (следовательно их загрузка будет происходить после прорисовки всей страницы) и только после этого содержимое блоков будет отображено в нужных местах. Это называется . Все серьезные проекты сегодня стараются как можно быстрее перейти на новую технологию загрузки. Тем более, что это абсолютно легко.

Есть несколько подходов. Начну по порядку.

script src= type= "text/javascript" >

Асинхронная загрузка скрипта HTML5

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

< script async src= "http://www.site.ru/script.js" type= "text/javascript" >

< script defer src= "http://www.site.ru/script.js" type= "text/javascript" >

Чем же отличаются атрибуты async и defer

В обоих случаях мы получаем асинхронную загрузку скриптов. Разница заключается только в моменте, когда скрипт начинает выполнятся. Скрипт с атрибутом async выполнится при первой же возможности после его полной загрузки, но до загрузки объекта window. В случае использования атрибута defer – скрипт не нарушит порядок своего выполнения по отношению к остальным скриптам и его выполнение произойдет после полной загрузки и парсинга страницы, но до события DOMContentLoaded объекта document.

К сожалению, этот механизм на сегодняшний день не работает во всех браузерах (особенно это касается IE). Также не будет работать, если в файле script.js есть строки document.write .

Асинхронная загрузка javascript скриптом от Google

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

Чтобы использовать, просто заменяем

на

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

Получится так:

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

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

Лучшая рабочая асинхронная загрузка javascript

Универсальный способ для всех браузеров. Работает даже с document.write

В том месте страницы, где нужно реально отобразить наш элемент создаем пустой div блок:

< div id= "script_block" class = "script_block" >

В самом конце страницы перед вставляем скрипт для асинхронной загрузки файлов:

< div id= "script_ad" class = "script_ad" style= "display:none;" > Здесь любой файл или скрипт, который нужно загрузить. < script type= "text/javascript" > // переместить его в реальную позицию отображения document. getElementById("script_block" ) . appendChild(document. getElementById("script_ad" ) ) ; // показать document. getElementById("script_ad" ) . style. display = "block" ;

В самых старых версиях IE (6 и ниже) асинхронная загрузка к сожалению не работает, но таких пользователей уже практически нет. Все остальные браузеры и сервисы успешно пользуются современной ускоренной загрузкой web-страниц.

Современные веб-страницы сильно перегружены файлами javascript. Это ведет к замедлению загрузки и последующего отображения страницы. В худших условиях посетителю сайта приходится ждать до 30 секунд.

Ускоряем загрузку html страниц

Современное использование JavaScript

Современные веб-страницы сильно перегружены файлами javascript. Это ведет к замедлению загрузки и последующего отображения страницы. В худших условиях (медленное подключение к Интернету, много javascript файлов) посетителю сайта приходится ждать до 30 секунд.

HTML устроен так, что веб-страница загружается, синхронно (строка за строкой) загружая по очереди все включенные в html-код элементы.

Выход есть: поместить явавские строки в конец html документа (следовательно их загрузка будет происходить после прорисовки всей страницы) и только после этого содержимое блоков будет отображено в нужных местах. Это называется .

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

Есть несколько подходов. Начну по порядку.

< script src= "//www.site.ru/script.js" type= "text/javascript" >

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

< script async src= "//www.site.ru/script.js" type= "text/javascript" >

< script defer src= "//www.site.ru/script.js" type= "text/javascript" >

Чем же отличаются атрибуты async и defer

В обоих случаях мы получаем асинхронную загрузку скриптов. Разница заключается только в моменте, когда скрипт начинает выполнятся. Скрипт с атрибутом async выполнится при первой же возможности после его полной загрузки, но до загрузки объекта window. В случае использования атрибута defer - скрипт не нарушит порядок своего выполнения по отношению к остальным скриптам и его выполнение произойдет после полной загрузки и парсинга страницы, но до события DOMContentLoaded объекта document.

К сожалению, этот механизм на сегодняшний день не работает во всех браузерах (особенно это касается IE). Также не будет работать, если в файле script.js есть строки document.write .

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

Чтобы использовать, просто заменяем

на

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

Получится так:

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

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

Универсальный способ для всех браузеров. Работает даже с document.write

В том месте страницы, где нужно реально отобразить наш элемент создаем пустой div блок:

< div id= "script_block" class = "script_block" >

В самом конце страницы перед вставляем скрипт для асинхронной загрузки файлов:

< div id= "script_ad" class = "script_ad" style= "display:none;" > Здесь любой файл или скрипт, который нужно загрузить. < script type= "text/javascript" > // переместить его в реальную позицию отображения document. getElementById("script_block" ) . appendChild(document. getElementById("script_ad" ) ) ; // показать document. getElementById("script_ad" ) . style. display = "block" ;

В самых старых версиях IE (6 и ниже) асинхронная загрузка к сожалению не работает, но таких пользователей уже практически нет. Все остальные браузеры и сервисы успешно пользуются современной ускоренной загрузкой web-страниц.