admin / 26.01.2018

Ответы@Mail.Ru: Отложенная загрузка css ?

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

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

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

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

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

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

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

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

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

<script type=»text/javascript»> (function() { function async_load(){ var s = document.createElement(‘script’); s.type = ‘text/javascript’; s.async = true; s.src = ‘URL файла’; document.getElementsByTagName(‘head’)[0].appendChild(script); } if (window.addEventListener) { window.addEventListener(‘load’, async_load, false); } else if (window.attachEvent) { window.attachEvent(‘onload’, async_load); } })(); </script>

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

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

<script type=»text/javascript»> (function() { function async_load(){ [ ‘URL_файла_1.js’, ‘URL_файла_2.js’, ‘URL_файла_3.js’ ].forEach(function(src) { var s = document.createElement(‘script’); s.type = ‘text/javascript’; s.async = true; s.src = src; document.getElementsByTagName(‘head’)[0].appendChild(script); }); } if (window.addEventListener) { window.addEventListener(‘load’, async_load, false); } else if (window.attachEvent) { window.attachEvent(‘onload’, async_load); } })(); </script>

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

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

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

<script src=»https://steptosleep.ru/wp-content/uploads/2018/06/98516.jpg» type=»text/javascript» async></script> <script src=»https://steptosleep.ru/wp-content/uploads/2018/06/98516.jpg» type=»text/javascript» defer></script>

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

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

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

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

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

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

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

<script src=»https://steptosleep.ru/wp-content/uploads/2018/06/99075.jpg»></script> <script extsrc=»https://steptosleep.ru/wp-content/uploads/2018/06/41537.jpg»></script> <script asyncsrc=»https://steptosleep.ru/wp-content/uploads/2018/06/41537.jpg»></script>

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

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

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

Оказывается, что на практике добиться оптимальной кросс браузерной загрузки JavaScript скриптов, которые не блокируют отображение сложно, а порой невозможно. Наиболее оптимальный способом является добавление <script type=»text/javascript» src=»https://steptosleep.ru/wp-content/uploads/2018/06/24321.jpg»></script> в конец документа перед закрывающимся тегом body. Из за ограничения разных браузеров и самого HTML такой вариант загрузки, который не блокирует отображение, можно считать наиболее простой.

Joomla 2.5: Оптимизация js и Асинхронная загрузка JavaScript

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

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

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

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

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

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

  1. Объединяем все JavaScript файлы и размещаем то, что получилось перед закрывающим тегом сайта.
  2. Объединяем все 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()). Всё, что требуется от вас, это вставить код следующего содержания в файл вашего сайта.

add_action(’wp_enqueue_scripts’, ‘true_peremeshhaem_jquery_v_futer’);   function true_peremeshhaem_jquery_v_futer(){// снимаем стандартную регистрацию jQuery wp_deregister_script(’jquery’);   // регистрируем для подключения в футере, описание параметров — в документации функции (ссылка чуть выше) wp_register_script(’jquery’, includes_url(’/js/jquery/jquery.js’), false, null, true);   // подключаем wp_enqueue_script(’jquery’);   }

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

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

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

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

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

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

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

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

  1. Копируете содержимое таблицы стилей плагина и вставляете его в конец основного файла стилей — .
  2. Проверяете, проставлены ли в данных стилях относительные ссылки на изображения, например . Если да, то либо заменяете их на абсолютные, либо переносите изображения из плагина в папку с темой.
  3. Заходите в настройки плагина и смотрите, есть ли возможность где-нибудь снять галочку и не подключать CSS плагина. В «Contact Form 7» такой возможности нет, а значит мы переходим к следующему пункту.
  4. Отрубаем файлы через . Для стилей «Contact Form 7» код будет следующий:
    add_action(’wp_print_styles’, ‘true_otkljuchaem_stili_contact_form’, 100); // по идее вы можете использовать и хук wp_enqueue_scripts, хотя конкретно его я не тестировал   function true_otkljuchaem_stili_contact_form(){ wp_deregister_style(’contact-form-7’); // в параметрах — ID подключаемого файла}

Также иногда при помощи условных тегов файлы плагинов (как CSS, так и JS) отключают только с тех страниц, на которых они не используется.

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

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

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

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

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

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

<head> <title> Блог Лесного Владислава </title> <link href=»/assets/css/main.css?ver=1.0″ type=»text/css» rel=»stylesheet» /> <link href=»/assets/css/prettify.css» type=»text/css» rel=»stylesheet» /> <script src=»https://steptosleep.ru/wp-content/uploads/2018/06/50418.jpg»></script> <meta charset=»utf-8″ /> <meta name=»viewport» content=»initial-scale=1.0, user-scalable=no» /> </head>

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

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 src=»https://steptosleep.ru/wp-content/uploads/2018/06/50418.jpg»></script>

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

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

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

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

<head> … <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/6393.jpg»></script> <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/21229.jpg»></script> <script src=»https://steptosleep.ru/wp-content/uploads/2018/06/26312.jpg»></script> <script src=»https://steptosleep.ru/wp-content/uploads/2018/06/80419.jpg»></script> <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/36331.jpg»></script> </head>

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

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

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

<head> … <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/26695.jpg»></script> <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/62453.jpg»></script> <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/47547.jpg»></script> <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/22007.jpg»></script> <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/19941.jpg»></script> </head>

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

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

Атрибут defer

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

<head> … <script defer src=»https://steptosleep.ru/wp-content/uploads/2018/06/26695.jpg»></script> <script defer src=»https://steptosleep.ru/wp-content/uploads/2018/06/62453.jpg»></script> <script defer src=»https://steptosleep.ru/wp-content/uploads/2018/06/47547.jpg»></script> <script defer src=»https://steptosleep.ru/wp-content/uploads/2018/06/22007.jpg»></script> <script async src=»https://steptosleep.ru/wp-content/uploads/2018/06/19941.jpg»></script> </head>

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»:

sergeiss

8.12.2016 — 09:02

Владимир55, погугли на тему 'lazy loading'. Эта штуковина позволяет подгружать необходимые файлы по мере необходимости, а не все сразу. Можно применить к любому файлу, будь то JS или CSS. При этом, естественно, осуществляется контроль, был ли уже загружен этот файл.
Затем, после загрузки, когда она заведомо завершена, можно вызвать callback, который уже будет использовать данные из этого файла.
Lazy loading в чем-то похож на require_once в ПХП. И это название lazy loading не относится к какому-то определенному скрипту, это скорее название алгоритма/паттерна.

Цитата (FatCat @ 8.12.2016 — 02:30)
1. Чем это лучше чем write()?
2.

Асинхронная и отложенная загрузка

А нафига вообще?

1. Потому что надо осуществлять контроль, не был ли уже загружен этот файл. Если уже загрузили — ничего не делаем. Иначе грузим.

В итоге получаем lazy loading, описанный мной в предыдущем абзаце
2. Чтобы увеличить скорость начальной загрузки страницы. И чтобы уменьшить трафик: если что-то не потребуется, то это вообще не будет загружено.

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

Владимир55

8.12.2016 — 09:52

Сама идеология lazy loading мне представляется верной и весьма своевременной. И она, конечно же, способна дать гораздо больше, чем просто упорядочивание загрузки CSS. Полагаю, что на графике и видео выиграть можно больше.

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

У операторов есть норма выработки за день и девочки не будут заниматься никакими кодами. Им нужно вносить инфу с помощью редактора — быстро и много.

Но, в принципе, надо эту идею иметь в виду.

А если сейчас, применительно к поставленному вопросу, подкачку двух файлов сделать так:
function loadCss(href){
varlink=document.createElement("link");
link.rel ="stylesheet";
link.href=href;
document.head.appendChild(link);
}
loadCss(‘file1.css’);
loadCss(‘file2.css’);

Цитата (sergeiss @ 8.12.2016 — 08:02)
Потому что надо осуществлять контроль, не был ли уже загружен этот файл.

С контролем через DOM? Месье знает толк в извращениях.

_____________
Бесплатному сыру в дырки не заглядывают…

sergeiss

8.12.2016 — 16:25

Цитата (FatCat @ 8.12.2016 — 12:40)
Цитата (sergeiss @ 8.12.2016 — 08:02)
Потому что надо осуществлять контроль, не был ли уже загружен этот файл.

С контролем через DOM? Месье знает толк в извращениях.

CSS? Нет проблем 🙂

$(‘html’).context.styleSheets

JS? Аналогично:
$(‘html’).context.scripts

Анализируем и, если нету в списке, то грузим.

PS. Можно и без jQuery обойтись
document.getElementsByTagName(‘head’)[0].childNodes

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

Быстрый ответ:

Powered by dgreen

FILED UNDER : IT

Submit a Comment

Must be required * marked fields.

:*
:*