Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 11.02.2019, 14:42
Аватар для Duda.Ml1986@gmail.com
Профессор
Отправить личное сообщение для Duda.Ml1986@gmail.com Посмотреть профиль Найти все сообщения от Duda.Ml1986@gmail.com
 
Регистрация: 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 => {}
        );
    }
Ответить с цитированием
  #2 (permalink)  
Старый 11.02.2019, 14:54
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 2,952

Вам стоит добавить изображениям 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.
Ответить с цитированием
  #3 (permalink)  
Старый 11.02.2019, 21:22
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,283

Сообщение от 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
Ответить с цитированием
  #4 (permalink)  
Старый 11.02.2019, 22:38
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 2,952

Malleys, я правильно понял, что вы предлагаете добавить логику, по которой сервер будет отдавать пользователю статику?
В противном случае этот lazy-load, как собаке пятая лапа.

upd. да и с логикой такая же ненужная хрень. С такой ленивой загрузкой на сервер будет отправляться в 2 раза больше запросов.
Я что-то упустил или вы действительно описали не очень хороший метод реализации?

Последний раз редактировалось Nexus, 11.02.2019 в 22:43.
Ответить с цитированием
  #5 (permalink)  
Старый 11.02.2019, 23:17
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 11,181

Malleys,
Nexus,

вот как ребята выкручиваются. )
Ответить с цитированием
  #6 (permalink)  
Старый 11.02.2019, 23:44
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,283

Сообщение от 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 можно сделать более интересные вещи!
Ответить с цитированием
  #7 (permalink)  
Старый 12.02.2019, 00:34
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 27,110

Malleys,
то есть в примере изначально картинок нет, и они погружаются потом по мере скролла?
Ответить с цитированием
  #8 (permalink)  
Старый 12.02.2019, 08:17
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 2,952

Malleys,
Сообщение от Malleys
Вообще это круто, да?
Да, это круто)
Первый раз встречаю такой способ реализации.
Спасибо, что поделились.
Ответить с цитированием
  #9 (permalink)  
Старый 12.02.2019, 10:46
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 27,110

Сообщение от Nexus
Спасибо, что поделились.
присоединяюсь, только не могу увидеть результат, возможно не туда смотрю или что-то не знаю или не понимаю.(Firefox, Google Chrome)
Ответить с цитированием
  #10 (permalink)  
Старый 12.02.2019, 11:09
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 2,952

Сообщение от рони
то есть в примере изначально картинок нет, и они погружаются потом по мере скролла?
Изначально картинки есть, но service worker подменяет их заглушками (если в адресе изображения есть параметр "lazy"), т.е. они (изображения) фактически не загружаются.
Оригинальные изображения (вместо заглушек) загружаются, когда observer удаляет из их адреса параметр "lazy", т.к. в адресе изображения названный параметр отсутствует, то worker больше не препятствует запросу к серверу.

Здесь видно момент, когда заглушка заменяется оригинальным изображением:
https://plnkr.co/edit/ed1gNMgZWTA4IT5bwZ41?p=preview
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Загрузка изображений (миниатюр) Siend Общие вопросы Javascript 2 07.09.2015 18:51
Глючит загрузка в popup через load() zukalo jQuery 4 26.06.2011 11:18
IE, загрузка <form> через jshttprequest, <input type='submit'>' Jerlek Events/DOM/Window 1 06.05.2011 11:48
Простая загрузка файла с ajax через форму Djeman AJAX и COMET 9 03.05.2011 04:07
Jquery. загрузка части документа через ajax-запрос InviS jQuery 8 01.03.2010 17:47