Источник: Nuances of Programming
Изображения составляют огромный процент содержания веб-страниц. Однако чем больше изображений, тем медленнее загружается страница.
Большое количество изображений на сайте значительно влияет на его производительность. Отложенная загрузка — это концепция, разработанная для ограничения количества загружаемых ресурсов во время загрузки страницы.
Что такое отложенная загрузка?
Самыми важными составляющими производительности приложений являются время отклика и потребление ресурсов.
Отложенная загрузка помогает снизить риск возникновения некоторых проблем с производительностью веб-приложений до минимума. Она контролирует следующие параметры:
- Время отклика — это время, которое требуется для того, чтобы веб-приложение загрузилось, а UI-интерфейс начал реагировать на запросы пользователей. Отложенная загрузка оптимизирует время отклика с помощью разделения кода и загрузки необходимого бандла.
- Потребление ресурсов. Если загрузка веб-сайта длится более трех секунд, 70% пользователей покидают веб-сайт. При отложенной загрузке объем загружаемых ресурсов сокращается благодаря загрузке только необходимого на данном этапе бандла кода.
Отложенная загрузка ускоряет время загрузки приложения, загружая ресурсы по запросу.
Преимущества отложенной загрузки:
- Высокая производительность при начальной загрузке.
- Загрузка меньшего количества ресурсов при начальной загрузке.
Отложенная загрузка изображений с помощью Intersection Observer
Загрузка изображений или ресурсов, не находящихся в поле зрения пользователя, не имеет смысла. В первую очередь загружаются изображения в окне просмотра, затем при прокрутке страницы также загружаются и помещаются в представление изображения, которые попадают в окно просмотра.
Рассмотрим изображение выше. Веб-браузер и веб-страница загружены. Изображения IMG_1 и IMG_2 находятся в окне просмотра (видны пользователю и находятся в рамках представления браузера).
Изображения IMG_3 и IMG_4 находятся вне зоны видимости пользователя. Таким образом, производительность сайта заметно улучшится, если IMG_1 и IMG_2 будут загружены в первую очередь, а IMG_ 3 и IMG_4 позже по очереди при прокрутке вниз.
Но как определить, когда элемент появляется в представлении? Современный браузер предоставляет новый Intersection Observer API, с помощью которого можно определить, когда элемент попадает в окно просмотра.
Intersection Observer
Intersection Observer API предоставляет асинхронное наблюдение изменений в видимости элементов или относительной видимости двух элементов по отношению друг к другу.
Для отложенной загрузки изображений нужно определить элемент с шаблоном разметки:
<img class="lzy_img" src="lazy_img.jpg" data-src="real_img.jpg" />
Так выглядит отложено загруженный элемент изображения.
Класс определяет элемент как отложено загруженный элемент img. Атрибут src передает отложено загруженному изображению исходное изображение до загрузки реального изображения. Data-src содержит реальное изображение, которое будет загружено в элемент при появлении в окне просмотра браузера.
Теперь переходим к написанию логики отложенной загрузки. Как было сказано выше, для определения видимости элемента по отношению к документу в браузере мы используем Intersection Observer.
Сначала создаем экземпляр Intersection Observer:
const imageObserver = new IntersectionObserver(...);
IO принимает функцию в конструкторе, которая обладает двумя параметрами: первый содержит массив, состоящий из элемента для наблюдения, а второй содержит экземпляр IO.
const imageObserver = new IntersectionObserver((entries, imgObserver) => {
//...
});
- entries: содержит в массиве элементы, находящиеся в окне просмотра браузера.
- imgObserver: экземпляр IntersectionObserver.
Поскольку entries — это массив, то для него необходимо выполнить цикл, чтобы получить находящиеся внутри элементы и выполнить отложенную загрузку для каждого из них.
Затем нужно проверить, находится ли каждый entry в окне просмотра. Если entry пересекается с окном просмотра, то устанавливаем значение атрибута data-src для атрибута src в элементе img.
Проверяем, находится ли entry в окне видимости браузера if(entry.isIntersecting) {...}. Если да, то сохраняем экземпляр HTMLImgElement элемента img в переменной lazyImage. Затем устанавливаем атрибут src, присвоив его значению набора данных src. При этом изображение, сохраненное в data-src, загружается в элемент img. Предыдущее изображение lazy_img.jpg заменяется в браузере реальным изображением.
Теперь нужно вызвать imageObserver для начала наблюдения за элементами img:
imageObserver.observe(document.querySelectorAll('img.lzy_img'));
Объединяем все элементы с классом lzy_img в документе document.querySelectorAll('img.lzy_img') и передаем в imageObserver.observer(...).
imageObserver.observer(...) выбирает массив элементов и прослушивает их, чтобы узнать о пересечении их видимости с браузером.
Чтобы увидеть демо отложенной загрузки, нужно запустить проект Node:
mkdir lzy_img
cd lzy_img
npm init -y
Создайте файл index.html:
touch index.html
Добавьте в него следующее:
У нас есть 5 отложенных изображений, каждое из которых содержит lazy_img.jpg, а также несколько реальных изображений для загрузки.
Необходимо создать свои изображения:
Я создал lazy_img.jpg в Windows Paint, а реальные изображения (img_*.jpg) взял из Pixabay.com.
Обратите внимание, что я добавил console.log в функцию обратного вызова IntersectionObserver. Благодаря этому можно узнать, для каких изображений применяется отложенная загрузка.
Для использования файла index.html нужно установить http-сервер:
npm i http-server
Теперь добавляем свойство start в раздел сценариев в package.json.
scripts": {
"start": "http-server ./"
}
Теперь запустите npm run start в терминале.
Откройте браузер и перейдите к 127.0.0.1:8080. Загруженный index.html будет выглядеть следующим образом:
Изображения показывают lazy_img.jpg, и поскольку <img class="lzy_img" src="lazy_img.jpg" data-src="img_1.jpg" /> находится в окне просмотра, то загружается реальное изображение img_1.jpg.
Другие изображения не загружаются, так как они не находятся в представлении браузера.
Здесь есть небольшая проблема. При прокрутке img в представление загружается его изображение, однако при следующей прокрутке того же img в представление, браузер снова пытается загрузить реальное изображение.
Это серьезно повлияет на производительность сайта.
Чтобы решить эту проблему, нужно отписать IntersectionObserver от img, для которого уже загружено реальное изображение, а также удалить класс lzy из элемента img.
Редактируем код следующим образом:
Полная версия кода
Заключение
Мы рассмотрели отложенную загрузку изображений с помощью IntersecionObserver API, а затем реализовали демо-версию с настройкой кода отложенной загрузки в JS.
Читайте нас в телеграмме и vk
Перевод статьи Chidume Nnamdi 🔥💻🎵🎮: Lazy Loading Images using the Intersection Observer API