11.02.2019, 14:42
|
|
Профессор
|
|
Регистрация: 01.09.2011
Сообщений: 263
|
|
Ленивая загрузка изображений через Promise. Цепочка.
Здравствуйте,
Нужно было сделать отложенную загрузку изображений.
Для этого перед выводом html все src для img заменил на data-src. (php)
Что бы не грузились изначально.
Потом через Promise создавал изображения с путями из спрятанных файлов, параметр брался из data-src. Когда созданное изображение загружалось, я добавлял отсутствующий атрибут src скрытому изображению.
Вопрос в том как сделать загрузку в цепочке. То есть загрузка одного изображения и его полная загрузка вызывала бы загрузку другого изображения. Сейчас все создаётся одновременно и все файлы грузятся параллельно(я так думаю).
images_sidebar = $('#sidebar_menu_news_container img[data-src]');
$.each( images_sidebar, function( key, value ) {
lazeImageLoad(value);
});
function lazeImageLoad(image) {
let promise = new Promise((resolve, reject) => {
img = document.createElement('img');
img.src = $(image).attr('data-src');
if (img.complete) {
resolve(image);
} else {
img.addEventListener('load', resolve(image));
}
});
promise
.then(
result => {
image.src = $(image).attr('data-src');
},
error => {}
);
}
|
|
11.02.2019, 14:54
|
Профессор
|
|
Регистрация: 04.12.2012
Сообщений: 3,790
|
|
Вам стоит добавить изображениям src указывающий на изображение-заглушку.
Подгружать настоящие изображения стоит только тогда, когда пользователь уже проскроллил страницу до изображения либо через пару десятков пикселей уже это сделает (т.е. изображение фактически окажется на дисплее пользователя).
Подгружать изображения поштучно особого смысла нет, если очень переживаете за производительность сервера при отдаче статики, то стоит посмотреть в сторону протокола http2.
Решение вашей проблемы без обещаний (недостает обработки ошибок):
const queue=document.querySelectorAll('img[data-src]');
(function loadImage(){
if(!queue.length)
return;
const node=queue.shift();
node.onload=loadImage;
node.src=this.dataset.src;
})();
Последний раз редактировалось Nexus, 11.02.2019 в 14:56.
|
|
11.02.2019, 21:22
|
|
Профессор
|
|
Регистрация: 20.12.2009
Сообщений: 1,714
|
|
Сообщение от Duda.Ml1986@gmail.com
|
все src для img заменил на data-src.
|
Теперь это у вас не картины (точней элемент находится в таком состояний, что он не представляет картинку) и если, что-то пойдёт не так, то совсем их не будет видно. Совсем!
Сообщение от Nexus
|
Вам стоит добавить изображениям src указывающий на изображение-заглушку.
|
src предназначен для того, чтобы указать путь к полной картинке.
Вопрос в том, чтобы эта картинка показывалась только тогда, когда окажется на экране пользователя. Но как отличить картинку, которая загрузилась, от картинки, которая ещё не загрузилась? Ведь вы можете захотеть показывать вместо неё заглушку!
Картинка может быть определена так <img src="pic.jpg">, но можно ведь, например, в search params указать, что это картинка для ленивой загрузки! <img src="pic.jpg?lazy"> И тогда можно сказать, что pic.jpg?lazy это заглушка, а удалив lazy мы получим настоящую pic.jpg, когда она попадёт в область видимости!
Вот пример, реализованный при помощи отслеживания запросов, если в search params есть lazy, то можно даже не делать запрос на сервер, ведь заглушка может быть выполнена при помощи CSS или SVG. Попадёт ли в область видимости узнаётся при помощи Intersection Observer API. Пример... https://plnkr.co/edit/PxM3Poomc4JfXT5BlnyN?p=preview
|
|
11.02.2019, 22:38
|
Профессор
|
|
Регистрация: 04.12.2012
Сообщений: 3,790
|
|
Malleys, я правильно понял, что вы предлагаете добавить логику, по которой сервер будет отдавать пользователю статику?
В противном случае этот lazy-load, как собаке пятая лапа.
upd. да и с логикой такая же ненужная хрень. С такой ленивой загрузкой на сервер будет отправляться в 2 раза больше запросов.
Я что-то упустил или вы действительно описали не очень хороший метод реализации?
Последний раз редактировалось Nexus, 11.02.2019 в 22:43.
|
|
11.02.2019, 23:17
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,990
|
|
Malleys,
Nexus,
вот как ребята выкручиваются. )
|
|
11.02.2019, 23:44
|
|
Профессор
|
|
Регистрация: 20.12.2009
Сообщений: 1,714
|
|
Сообщение от Nexus
|
я правильно понял, что вы предлагаете добавить логику, по которой сервер будет отдавать пользователю статику?
|
Нет, конечно же! Это может быть и динамически сгенерированное изображение. Это не важно, подойдёт любой ресурс, который разрешается как изображение поддерживаемое браузером!
Если на странице есть <img src="pic.jpg"> и <img src="pic.jpg?lazy">, то браузер сразу начнёт скачивать картинки, но мы можем отслеживать событие fetch, и следовательно решать, нужно ли, что-то скачивать с сервера или нет. Если в пути содержится параметр lazy, то мы можем сами составить ответ на этот запрос. Например, это может быть пустая SVG картинка.
const image = new Response(`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1">
</svg>
`, {
headers: { "Content-Type": "image/svg+xml" }
});
addEventListener("fetch", function(event) {
const { searchParams } = new URL(event.request.url);
if(searchParams.has("lazy")) {
event.respondWith(image.clone());
}
});
Этот код в отдельном файле(mediator.js), подключается к приложению так...
<script>
navigator.serviceWorker.register("mediator.js").then(console.log, console.error);
</script>
Это так, пример, а так там может быть своя логика, что делать при успешной регистрации или отторжении.
Весь прикол в том, что те картинки, которые имеют параметр lazy, это будут пустые SVG-картинки. И тут нужно отслеживать местоположение этих картинок, как только они оказываются в области видимости пользователя, удаляется параметр lazy, браузер опять начинает запрос, но поскольку в обработчике события нет подходящего условия, то будет скачана картинка с сервера.
Сообщение от Nexus
|
Я что-то упустил или вы действительно описали не очень хороший метод реализации?
|
Да, может быть вы не заметили Service Worker. Вообще это круто, да? Дописываешь lazy и оно не загружается, а потом убираешь из адреса lazy и оно загружается. И вёрстка простая <img src="pic.jpg?lazy">, а не <img class="lazy-loading-image" data-src="pic.jpg"> и пр. обёртки с <template>. Вообще, конечно, можно сделать так, чтобы параметр lazy не приписывать. Вообще супер! Конечно при помощи Service Worker можно сделать более интересные вещи!
|
|
12.02.2019, 00:34
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,103
|
|
Malleys,
то есть в примере изначально картинок нет, и они погружаются потом по мере скролла?
|
|
12.02.2019, 08:17
|
Профессор
|
|
Регистрация: 04.12.2012
Сообщений: 3,790
|
|
Malleys,
Сообщение от Malleys
|
Вообще это круто, да?
|
Да, это круто)
Первый раз встречаю такой способ реализации.
Спасибо, что поделились.
|
|
12.02.2019, 10:46
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,103
|
|
Сообщение от Nexus
|
Спасибо, что поделились.
|
присоединяюсь, только не могу увидеть результат, возможно не туда смотрю или что-то не знаю или не понимаю.(Firefox, Google Chrome)
|
|
12.02.2019, 11:09
|
Профессор
|
|
Регистрация: 04.12.2012
Сообщений: 3,790
|
|
Сообщение от рони
|
то есть в примере изначально картинок нет, и они погружаются потом по мере скролла?
|
Изначально картинки есть, но service worker подменяет их заглушками (если в адресе изображения есть параметр "lazy"), т.е. они (изображения) фактически не загружаются.
Оригинальные изображения (вместо заглушек) загружаются, когда observer удаляет из их адреса параметр "lazy", т.к. в адресе изображения названный параметр отсутствует, то worker больше не препятствует запросу к серверу.
Здесь видно момент, когда заглушка заменяется оригинальным изображением:
https://plnkr.co/edit/ed1gNMgZWTA4IT5bwZ41?p=preview
|
|
|
|