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

Детские товары 30.04.2019
Детские товары

Большинство (если не все) современных сайтов используют Javascript. Кнопки социальных сетей? Плагины? Даже шаблоны! В 99% случаев эти компоненты будут использовать Javascript. Это означает, что на ваших сайтах используются скрипты. Но скрипты замедляют скорость работы сайта. Сегодня мы хотим представить вам 2 плагина, которые позаботятся об этой проблеме.

Асинхронное и отложенное… что?

Перед тем, как мы начнем, вам следует учитывать три вещи:

  • Parser – это HTML в стадии загрузки
  • Net – это время, за которое загружается ваш скрипт
  • Execution – это время, за которое скрипт полностью загружен для работы в браузере.
  • В рамках обычной среды работы сайта HTML парсинг приостанавливается на время выполнения скриптов. Если ваш сайт похож на мой, то это означает, что пользователь, перед тем, как сможет воспользоваться вашим сайтом, должен будет немного подождать (загрузки вашего кода, дизайна, контента и так далее). Давайте взглянем на то, как выглядит обычная загрузка скрипта:

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

    Асинхронная загрузка скриптов – это лучшая опция. HTML-парсинг и загрузка скриптов будет продолжаться, но выполнение скриптов будет возможным только тогда, когда вся загрузка будет завершена. Это позволит вам максимально быстро представить контент сайта вниманию посетителей. Однако не все браузеры поддерживают асинхронную загрузку скриптов. Давайте взглянем на то, как происходит асинхронная загрузка:

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

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

    С чего начать?

    Итак, если Асинхронный javascript – это лучшая опция, позвольте представить вам лучший WordPress-плагин для асинхронной загрузки Javascript. Кто бы мог подумать, что называется он !

    Скачайте его, установите и – вы готовы к работе! Однако он будет конфликтовать с некоторыми плагинами, особенно если вы используете слайдеры. В настройках шаблонов WordPress зачасту присутствует такая функция. Вы можете исключить скрипты, которые должны загружаться мгновенно.

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

    Скачайте его, установите, и он начнет работу без каких-либо настроек, потому что в нем их просто-напросто нет. Он будет автоматически запускаться для тех пользователей, чьи браузеры не поддерживают асинхронную загрузку 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 файлы, 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 такой вариант загрузки, который не блокирует отображение, можно считать наиболее простой.

    / 26.01.2018

    С ростом скорости интернет соединения и увеличении мощности не только десктопных, но и мобильных устройств веб страницы стают более «тяжелыми». Количество и размер подключаемых файлов растет: 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. Это можно сделать путем добавления ключевого слова async или defer. Например:

    .jpg» type=»text/javascript» 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.

    .jpg»>.jpg»>

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

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

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

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

    Google PageSpeed: CSS стили и JavaScript скрипты, блокирующие загрузку страницы на WP

    В этом посту будет подразумеваться, что вы знакомы с инструментом Google по оптимизации скорости загрузки страниц сайта — PageSpeed Insights. Слушайте, да прямо сейчас вбейте туда свой сайт нажмите кнопку «Analize».

    Окей, а теперь — о чём этот пост?

    Вполне возможно, что в результатах проверки вашего сайта есть пункт «Eliminate render-blocking JavaScript and CSS in above-the-fold content».

    Я заметил, что этот пункт один из самых трудноразрешимых (трудоёмких) и практически на всех сайтах, даже на очень быстрых, он присутствует.

    Как его исправить в теории:

  • Объединяем все JavaScript файлы и размещаем то, что получилось перед закрывающим тегом сайта.
  • Объединяем все CSS, суём прямо перед JavaScript, которые мы уже переместили, затем выбираем из них те стили, которые необходимы для корректного отображения страницы, а в особенности её верхней части (первого экрана) и помещаем их в тег в сайта.
  • Как же обстоит дело на практике, и в данном конкретном случае — для сайтов на WordPress?

    1. Воспользуемся зависимостью других скриптов от jQuery

    В корректно состряпанной теме WordPress все CSS и JS файлы подключаются через wp_head() и wp_footer() — то есть в и в конце соответственно.

    Также у файлов есть зависимости, то есть например плагин должен подключаться после, а это значит, что если библиотека jQuery находится в wp_footer(), то FancyBox ну никак не может попасть в wp_head().

    Перемещаем jQuery в футер сайта

    Делается это очень просто — при помощи функций wp_deregister_script(), wp_register_script(), wp_enqueue_script() и хука (иногда используют хук в связке с is_admin()). Всё, что требуется от вас, это вставить код следующего содержания в файл вашего сайта.

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

    На этом наша работа с JS заканчивается, конечно прирост в скорости даст ещё и объединение скриптов (то есть снимаете их все с регистрации и потом просто подключаете свою объединенную версию) — но Google сейчас это уже не требует.

    2. Объединение CSS в WordPress

    Если объединение всех JavaScript в один файл — не всегда хорошая идея, то CSS-ки я бы рекомендовал объединять по возможности всегда.

    Помните скриншот в самом начале статьи (10 blocking CSS resources )? Откуда берется такое количество файлов стилей, ведь разработчик темы наверное понимал, что делает?

    Ответ — из плагинов.

    Например плагин «Contact Form 7» подключает свою собственную таблицу стилей, и хотя сама по себе она невелика, то лучше всё же избежать лишних HTTP-запросов.

    Давайте пошагово разберем как.

  • Копируете содержимое таблицы стилей плагина и вставляете его в конец основного файла стилей — .
  • Проверяете, проставлены ли в данных стилях относительные ссылки на изображения, например. Если да, то либо заменяете их на абсолютные, либо переносите изображения из плагина в папку с темой.
  • Заходите в настройки плагина и смотрите, есть ли возможность где-нибудь снять галочку и не подключать CSS плагина. В «Contact Form 7» такой возможности нет, а значит мы переходим к следующему пункту.
  • Отрубаем файлы через. Для стилей «Contact Form 7» код будет следующий:
  • Также иногда при помощи условных тегов файлы плагинов (как CSS, так и JS) отключают только с тех страниц, на которых они не используется.

    Ок, с «Contact Form 7» разобрались, а как узнать ID файлов CSS других плагинов?

    Да легко, открываем исходный код страницы и видим там подобную картину:

    Также есть плагин, который позволит выполнить объединение CSS и JavaScript автоматически — JS & CSS Script Optimizer.

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

    Порядок загрузки страницы браузером

    Браузер загружает страницу последовательно. Особенно это актуально для внешних ссылках на файлы — css и javascript. Возьмем для примера блок для сайта lesnoy.name.

    Блог Лесного Владислава

    На данном сайте подгружается всего три внешних файла.

    2 из них — css стили, и один — js-файл. Но это пример простого сайта, зачастую подгружаются десятки внешних файлов и это существенно влияет на скорость загрузки страницы.

    Ускорение отображения страницы в браузере

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

    Т.е., из примера выше видно, что браузер загрузит заголовок сайта (title), затем встретит ссылку на внешний css файл main.css и пойдет загружать его. После загрузки он его обрабатывает и идет дальше — встречает второй css-файл, опять откладывает обработку страницы на потом и работает с prettify.css. Так же и с prettify.js. И лишь потом он принимается за отображения остальной страницы, уже применяя все обработанные ранее css-правила из css файлов и js-кол из javascript файлов.

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

    Можно, конечно. Самый банальный, но от этого не менее действенный метод — перенос всех не приоритетных внешних файлов с хедера сайта в футер. Т.е. с head-блока как можно ближе к тегу.

    Под не приоритетными файлами я подразумеваю те, которые не критичны для функциональности или внешнего вида сайта. Хороший способ разделить большой css или js файл на два — первый маленький хранит в себе то, что должно загрузиться как можно быстрее и размещается в head-секции, а второй и объемный содержит все остальное и располагается как можно ниже в html-коде страницы, не влияя на скорость отображения контента страницы.

    Но с приходом html5 можно сделать это проще и красивее. У тега script добавлен параметр async и defer .

    Атрибут async

    Атрибут тега script async делает загрузку js-файлов асинхронным. Те, кто умеют программировать на JS точно знают, как это — асинхронно. Тем же, кто не умеет — расскажу: браузер встречает ссылку на внешний javascript файл (тег script с параметром src), начинает выполнять его загрузку и обработку, но не останавливает при этом загрузку и обработку основной страницы.

    Т.е. делает это параллельно. Как раз то, что нам и нужно! И при этом не требуется переносить этот тег в футер (тем более не во всех CMS-системах это просто сделать).

    Недостаток атрибута async

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

    В данном примере я не могу точно сказать, какая последовательность выполнения этих js-файлов будет. Я могу точно сказать лишь то, что script4 загрузиться после script3 из-за отсутствия у них атрибута async. Но какой файл из script1.js, script2.js и script5.js загрузиться раньше я не знаю, т.к. они загружаются асинхронно.

    Вставить/изменить ссылку

    «Да и какая нам разница?» — спросите вы. Но она появляется в том случае, если выполнения одного js-скрипта зависит от другого. Такое сейчас сплошь и рядом и самый простой пример такой зависимости — jQuery.

    В данном случае очень велика вероятность получения ошибки JavaScript из-за того, что какой-либо из jQuery плагинов начнет выполнятся раньше, чем загрузиться сам jQuery.

    Что же делать?

    Атрибут defer

    Тут нас и выручает другой атрибут script-тега — defer.

    Deferred переводиться с английского языка как «отложенный».

    Соответственно deferred javascript load — отложенная загрузка javascript. Если у ссылки на внешний js-файл браузер встречает атрибут defer, то он откладывает загрузку и выполнения этих файлов до тех пор, когда вся страница не будет загружена и отображена. При этом он гарантирует такой же порядок выполнения скриптов, который изначально и был установлен в html-коде.

    Соответственно, в нашем примере с jQuery и его плагинами defer нас выручает, выполняя две задачи: время отображения страницы существенно уменьшается (браузер не блокирует отрисовку страницы для загрузки js-файлов, он откладывает загрузку на потом) и при этом мы избавляется от возможных ошибках, связанных с асинхронной загрузкой зависимых друг от друга js файлов.

    В примере выше скрипт other_script.js загрузиться асинхронно, т.к. он не зависит от какого-либо другого файла, а jQuery и его плагины загрузятся сразу после отображения страницы в следующем порядке: сначала jquery.min.js, затем по порядку plugin1.jquery.js, plugin2.jquery.js, plugin3.jquery.js.

    В итоге с приходом html5 и атрибутов defer и async мы можем намного гибче управлять порядком загрузки внешних js-файлов, тем самым повышая скорость отрисовки веб-страницы . А, главное, для пользователя будет создаваться впечатления значительного повышения скорости загрузки всего веб-сайта в целом , ведь уже через несколько секунд он увидит то, зачем пришел на сайт — информацию.

    Эта проблема была предварительно затронута в статье: «Как JavaScript тормозит Веб (и что с этим делать)?»

    Для начала определимся с самой проблемой. Событие window.onload используется программистами для старта их веб-приложения. Это может быть что-то довольно простое, например, выпадающее меню, а может быть и совсем сложное, как пример, запуск почтового приложения. Суть проблемы заключается в том, что событие onload срабатывает только после того, как загрузится вся страница (включая все картинки и другое бинарное содержимое). Если на странице много картинок, то можно заметить некоторую задержку между загрузкой страницы и тем моментом, когда она начнет фактически работать. На самом деле, нам нужно только узнать способ определить, когда DOM полностью загрузится, а не ждать еще и загрузку картинок.

    Mozilla впереди планеты всей

    У Mozilla (прим.: на данный момент Firefox является более актуальным, поэтому далее упоминается именно он ) есть (недокументированное) событие специально для этих целей: DOMContentLoaded . Следующий образец кода выполняет как раз то, что нам нужно в Mozilla-подобных браузерах (а также в Opera 9):

    // для Firefox if (document.addEventListener) { document.addEventListener("DOMContentLoaded", init, false); } А Internet Explorer?

    IE поддерживает замечательный атрибут для тега <script> : defer . Присутствие этого атрибута указывает IE, что загрузку скрипта нужно отложить до тех пор, пока не загрузится DOM. Однако, это работает только для внешних скриптов. Следует также заметить, что этот атрибут нельзя выставлять, используя другой скрипт. Это означает, что нельзя создать с этим атрибутом, используя DOM-методы, — атрибут будет просто проигнорирован.

    Используя этот удобный атрибут, можно создать мини-скрипт, который и будет вызывать наш обработчик onload:

    Условные комментарии

    Есть некоторая проблема с этим подходом. Другие браузеры проигнорируют атрибут defer и загрузят этот скрипт сразу же. Существует несколько способов, как можно с этим побороться. Моим любимым методом является использование условных комментариев (conditional comments ), чтобы скрыть «отложенный» скрипт:

    IE также поддерживает условную компиляцию (conditional compilation ). Следующий код будет JavaScript-эквивалентом для заявленного выше HTML-кода:

    // для Internet Explorer /*@cc_on @*/ /*@if (@_win32) document.write(""); /*@end @*/ Все так просто?

    И конечно же, нам нужно обеспечить поддержку для остальных браузеров. У нас есть только один выход — стандартное событие window.onload:

    // для остальных браузеров window.onload = init; Двойное выполнение

    Остается одна маленькая неприятность (кто сказал, что будет легко?). Поскольку мы устанавливаем событие onload для всех (оставшихся) браузеров, то init сработает дважды в IE и Firefox. Чтобы это обойти, нам нужно сообщить функции, что она должна выполняться только один раз. Итак, наш метод init будет выглядеть примерно так:

    function init() { // выходим, если функция уже выполнялась if (arguments.callee.done) return; // устанавливаем флаг, чтобы функция не исполнялась дважды arguments.callee.done = true; // что-нибудь делаем };

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

    Избавляемся от внешнего файла

    У описанного решения существует пара минусов:

    • Для IE нам требуется внешний JavaScript-файл
    • Не поддерживается Safari (Opera 9 поддерживает DOMContentLoaded)

    Большое спасибо Matthias Miller , теперь у нас есть решение и для Internet Explorer, которое не зависит от внешних файлов:

    // для Internet Explorer (используем условную компиляцию) /*@cc_on @*/ /*@if (@_win32) document.write(" "); var script = document.getElementById("__ie_onload"); script.onreadystatechange = function() { if (this.readyState == "complete") { init(); // вызываем обработчик для onload } }; /*@end @*/ И Safari тоже!

    Я позже почерпнул из листа рассылки jQuery , что, благодаря создателю jQuery, John Resig , существует решение и для Safari!

    if (/WebKit/i.test(navigator.userAgent)) { // условие для Safari var _timer = setInterval(function() { if (/loaded|complete/.test(document.readyState)) { clearInterval(_timer); init(); // вызываем обработчик для onload } }, 10); }

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

    Полное решение // Dean Edwards/Matthias Miller/John Resig function init() { // выходим, если функция уже выполнялась if (arguments.callee.done) return; // устанавливаем флаг, чтобы функция не исполнялась дважды arguments.callee.done = true; // что-нибудь делаем }; /* для Mozilla/Firefox/Opera 9 */ if (document.addEventListener) { document.addEventListener("DOMContentLoaded", init, false); } /* для Internet Explorer */ /*@cc_on @*/ /*@if (@_win32) document.write(""); var script = document.getElementById("__ie_onload"); script.onreadystatechange = function() { if (this.readyState == "complete") { init(); // вызываем обработчик для onload } }; /*@end @*/ /* для Safari */ if (/WebKit/i.test(navigator.userAgent)) { // условие для Safari var _timer = setInterval(function() { if (/loaded|complete/.test(document.readyState)) { clearInterval(_timer); init(); // вызываем обработчик для onload } }, 10); } /* для остальных браузеров */ window.onload = init;

    Рекомендуем почитать

    Наверх