Предварительная загрузка изображений. Управляем загрузкой изображений

Для игры нужно подгрузить заранее в районе 12 изображений, причем эти изображения могут варьироваться от случая к случаю. То есть сейчас мне нужно подгрузить одни 12 изображений (SVG), а завтра нужно будет другие 12. Поэтому вариант помещения их в не подходит, ибо в этом случае придется постоянно грузить все изображения, а понадобятся мне из них всего 12. Поэтому было решено подгружать их средствами JavaScript перед началом игры. Для этого я реализовал небольшой класс "AssetsPreloader", который, пока что, имеет единственный метод "preload", который принимает массив из объектов вида {src: "ссылка", id: "id"} и подгружает необходимые изображения путем простого создания экземпляра класса Image() (нативный).

Class AssetsPreloader { static preload(arr) { arr.map((a) => { let img = new Image(); img.src = a.src; img.id = a.id; (this.assets = this.assets || ).push(img); }); } }

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

Следующим в коде идет отрисовка первого кадра игры, где эти изображения уже используются. И, в общем-то, проблема в том, что отрисовка не происходит. До нее выполнение кода доходит, это я проверял, и после нее код выполняется, но сами изображения не отрисовываются. Насколько я понимаю, происходит это потому, что изображения не успевают загрузиться (даже несмотря на то, что загрузка их происходит с диска). Однако, если запросить отрисовку первого кадра прямо из консоли браузера, то все работает как надо и кадр рисуется нормально.

Весь код в общем и целом выглядит примерно так:

Class AssetsPreloader { static preload(arr) { arr.map((a) => { let img = new Image(); img.src = a.src; img.id = a.id; (this.assets = this.assets || ).push(img); this.done = true; }); } } AssetsPreloader.preload([ {src: "images/image.svg", id: "id_of_image"}, ... ]); // ... GAME.field.draw();

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

Прошу помощи. Интересует не только как, но и как наиболее правильно (best-practice, все такое).

P.S. Файл скрипта подключен к странице с атрибутом defer . При использовании, например, async , отрисовка либо происходит, либо нет (отчего зависит - не могу сказать). А вешать в сам код обработчики проверки загрузки страницы, готовности DOM или что-то в этом роде не хочу.

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

Но есть один нюанс, если событие hover возникает первый раз, то для загрузки изображения может потребоваться время. Пусть этот временной интервал будет и небольшим, но все же, иногда можно заметить короткую раздражающую задержку между наведением курсора над элементом и полным отображением изображения. Понятно, что в последующем, таких задержек не будет, так как браузеры добросовестно закешируют изображение. Но, как известно, первое впечатление от Вашего сайта должно быть только положительным, и не нужно его портить такими мелочами, тем более что их можно избежать. Как же решить такую, хоть и небольшую, но своеобразную проблему. Методов есть много, здесь наша веб студия познакомит Вас только с теми, которые решаются средствами css .

Первый прием заключается в том, что сразу же загружаем графическую составляющую, а потом убираем ее с видимой области при помощи свойства background-position, например установлением следующих смещений по x и y - -9999px -9999px. При наступлении события hover, применяем уже реальные значения, например, bottom left.

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

#random-unsuspecting-element { background: url(images/grass.png) no-repeat -9999px -9999px; }

#grass:hover { background: url(images/grass.png) no-repeat; }

Идея заключается в создании новых элементов, которые нужны только для предварительной загрузки изображений. Вы скажете, что это не самый лучший способ, ведь количество таких пустышек может быть огромным, решение же, далеко не будет элегантным. И Вы будете совершенно правы. Нам не нужны дополнительные элементы, так как мы можем со спокойной душой использовать и существующие. Все что нам необходимо, это использовать псевдоклассы:after или:before.

#something:before {

content: url("./img.jpg");

visibility:hidden;

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

Конечно же, можно применять для этих целей и javascript, но если Вам для создания сайта , достаточно будет приведенных выше решений, то почему бы ими и не воспользоваться.

  • Перевод
  • Tutorial

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

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


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

Например, чтобы задать соотношение сторон 4:3, можно использовать следующий CSS:

Img_wrapper{ position: relative; padding-top: 75%; overflow: hidden; } .img_wrapper img{ position: absolute; top: 0; width: 100%; opacity: 0; }
Для того, чтобы изображение отображалось в браузере только после полной подгрузки, необходимо добавить событие onload для изображения и использовать JavaScript, который будет обрабатывать событие:


function imgLoaded(img){ var $img = $(img); $img.parent().addClass("loaded"); };
Код функции внутри тега HEAD должен быть расположен в самом конце, после любого jQuery или другого плагина. После полной подгрузки изображения его необходимо показать на странице:

Img_wrapper.loaded img{ opacity: 1; }
Для эффекта плавного появления картинки можно использовать CSS3 transition:

Img_wrapper img{ position: absolute; top: 0; width: 100%; opacity: 0; -webkit-transition: opacity 150ms; -moz-transition: opacity 150ms; -ms-transition: opacity 150ms; transition: opacity 150ms; }
Живой пример этого способа можно .

Использование контейнера для множества изображений Предыдущий способ хорошо подходит для отдельных изображений, а что если на странице их много, например галерея фотографий или слайдер? Подгружать сразу все нецелесообразно - картинки могут много весить. Для решения этой проблемы можно заставить JavaScript"ом загружать только нужные в данный момент времени изображения. Пример HTML-разметки для слайдшоу:


Используем функцию slideLoaded(), чтобы контролировать процесс:

Function slideLoaded(img){ var $img = $(img), $slideWrapper = $img.parent(), total = $slideWrapper.find("img").length, percentLoaded = null; $img.addClass("loaded"); var loaded = $slideWrapper.find(".loaded").length; if(loaded == total){ percentLoaded = 100; // INSTANTIATE PLUGIN $slideWrapper.easyFader(); } else { // TRACK PROGRESS percentLoaded = loaded/total * 100; }; };
Подгруженным изображениям присваивается класс loaded, а также отображается общий прогресс. И снова, JavaScript должен быть помещен в конец тега HEAD, после всего остального.

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

var heroArray = [ "/uploads/hero_about.jpg", "/uploads/hero_history.jpg", "/uploads/hero_contact.jpg", "/uploads/hero_services.jpg" ]
Когда посетитель заходит на сайт, после загрузки главной страницы, начинают загружаться изображения в кэш. Для того, чтобы кэширование не мешало отображению текущего контента, необходимо функционал JavaScript добавить в событие window load:

Function preCacheHeros(){ $.each(heroArray, function(){ var img = new Image(); img.src = this; }); }; $(window).load(function(){ preCacheHeros(); });
Такой способ улучшает удобство использования сайта, однако дает дополнительную нагрузку на сервер. Это нужно иметь в виду при внедрении подобного функционала. Кроме того, необходимо обязательно учитывать возможные пути посетителей на сайте и кэшировать изображения, расположенные на страницах, которые пользователь вероятнее всего посетит. Чтобы понять такие пути по сайту, необходимо анализировать статистику посещаемости.

Загрузка по событию способ заключается в том, что изображения начинают подгружаться после определенного события. Это увеличивает производительность и экономит трафик пользователя. HTML-разметка:


Стоит заметить, что URL изображение задано в data-src, а не в src. Это необходимо, чтобы браузер не загружал картинку сразу. Вместо этого в src загружается прозрачный пиксель в GIF, заданный в base64, что уменьшает количество обращений к серверу.

Остается только при нужном событии изменить значение src на data-src. JavaScript позволяет загружать изображения постепенно:

Function lazyLoad(){ var $images = $(".lazy_load"); $images.each(function(){ var $img = $(this), src = $img.attr("data-src"); $img .on("load",imgLoaded($img)) .attr("src",src); }); }; $(window).load(function(){ lazyLoad(); };

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

Изображения, хорошие и качественные, являются главным преимуществом сайта. Но основной бедой в использовании изображений является их размер: обычно это не менее 50% от размера сайта и не менее 300 Кб на каждой странице составляются изображения (такой объем информации на мобильном телефоне загружается примерно 1,5 секунды, на стационарном компьютере - 0,2-0,3 секунды).

Что же с ними делать?

Последовательные изображения и PNG

Проблема с размером изображений является уже очень старой и хорошо изученной. Лучшее, что вы можете сделать прямо сейчас, - это использовать progressive (последовательные) JPEG формат для полноцветных изображений (фотографии) и PNG формат для всех других файлов (например, фоновых изображений или иконок).

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

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

«Ленивая» загрузка (lazy load)

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

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

Непростая задача, правда?

Улучшаем lazyload

Существует несколько реализаций lazyload - в частности, unveil - которые обошли первый недостаток: загрузка изображений может быть отложена ровно до того момента, когда мы покажем пользователю «готовый» сайт (обычно это момент готовности структуры страницы - DOMready - но иногда и полная загрузка страницы - onload). И начнем загружать все изображения сразу после этого события. Если пользователь потратит 2-3 секунды на первичное ознакомление с содержимым страницы, то для него загрузка изображений пройдет практически незаметно (браузер уже покажет, что страница готова). Если пользователь все же успеет начать просматривать страницу до того, как у него загрузятся все изображения, то на месте изображений вместо значка от браузера по умолчанию или пустого места будет индикатор загрузки.

Вполне элегантное решение, но его можно улучшить еще, если более тщательно подойти к последовательности загрузки страниц сайта. Рассмотреть, какие виджеты и когда загружаются: чтобы они не вклинились в процесс загрузки изображений. Расположить изображения на 1-2 поддоменах, если их больше 30 - так будет положительных эффект от параллельной загрузки изображений. Возможно, часть изображений перенести на событие полной загрузки, а часть - на событие готовности структуры страницы. В общем, исследовать процесс загрузки сайта более детально и оптимизировать пользовательское восприятие - чтобы сайт выглядел реактивным.

Пред-загрузка изображений (prefetch)

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

Техника предварительной загрузки изображений (preload или prefetch) активно используется в различных галереях изображениях - например, Яндекс.Фотки - пока вы просматриваете одно изображения, браузер уже загружает два-три предыдущих и два-три следующих. И покажет их практически моментально после перехода назад или вперед. И это будет реактивно!

Для интернет-магазина можно использовать ту же технику при просмотре отдельных товаров - подгружая сразу изображения из галереи или похожих товаров из рекомендательного сервиса. Это сократит объем передаваемой информации от сайта к пользователю после перехода по новой ссылке и визуально ускорит сайт.

Заключение и список действий

Итак, масса полезной информации. Что же конкретно делать? Вам нужно пройти по следующему списку и проверить, все ли у вас на сайте хорошо. Если нет - то принять соответствующие меры:

  • Полноцветные изображения создаются в последовательных JPEG? Если нет и можно сохранять изображения с потерями качества, то нужно настроить этот формат.
  • Все остальные изображения в PNG? Если нет, то нужно настроить именно этот формат. Дополнительно рекомендуется оптимизировать PNG изображения пакетно или при помощи сервисов .
  • Все ли изображения отображаются в естественных размерах? Часто физические размеры (высота и ширина) у изображения больше размера видимого изображения. Это приводит к рудиментам по качеству и заставляет загружать значительно больше данных, чем нужно. Измените размеры изображений к используемым на сайте (если нужно, создайте дубликаты в других размерах).
  • Изображений на странице больше 20 и они не помещаются на первых двух экранах? Нужно использовать какое-либо решение lazyload для сокращения объема первоначально загружаемой информации.
  • На сайте кроме изображений используется несколько виджетов и кодов статистики? Проверьте диаграмму загрузки сайта и убедитесь, что ценные изображения при отложенной загрузке передаются пользователю в первую очередь.
  • Нужно максимально ускорить сайта, и все пункты уже сделаны? Настройте предварительную загрузку изображений при переходах по страницам сайта. Изучите сценарии использования сайта - и подстройте логику загрузки изображений под них.
  • Это, в принципе, все. Стоит напомнить, что Айри автоматически приводит изображения к минимальному размеру и наилучшему формату без потери качества, а также может динамически выставить правильные размеры для изображений и отложить их загрузку.

    Для чего нам нужна предварительная загрузка изображений? Чаще всего мы используем её для качественно прорисовки интерфейсов, элементов управления сайта.Пример:Есть скрипт галереи или текстовые блоки с возможностью перемещения (туда/сюда). За управление перемещением отвечают графические стрелки. При наведении на стрелку её изображение заменяется на другое.
    Что делает браузер при наведении? Он отправляет запрос на изображение к серверу. Даже при очень быстром ответе будет замечен эффект «подмаргивания». Если выполнить предварительную загрузку изображений - этого не произойдёт.ПрименениеВ современной вёрстке этот подход используется редко. Гораздо предпочтительнее использовать CSS Sprites. Но, если нет такой возможности и Вам действительно это надо - добро пожаловать под кат.

    Var imgPath = "/tpl/images/"; // путь к каталогу с изображениями // список изображений var preloadImagesList = Array("about_hover.jpg", "news_hover.jpg", "photo_hover.jpg", "video_hover.jpg", "contacts_hover.jpg");// /*******************************/ // функция предварительной загрузки function preloadImages(images){ for(var i = 0; i < images.length; i++){ var image = images[i]; $("").attr("src", imgPath + image); }//for }//preloadImages /*******************************/ //вызов функции $().ready(function(){ preloadImages(preloadImagesList); })