Usar o carregamento lento de imagens para melhorar o desempenho de projetos da web é uma técnica popular de otimização. O fato é que as imagens são recursos "pesados" e repletos de sites modernos. Já publicamos algo sobre isso.
Aqui, você pode ler sobre o que o carregamento lento deu ao site do Walmart e aprender como usar o IntersectionObserver nos projetos React.
Aqui está um artigo sobre como otimizar sites estáticos.
Aqui está um material recente sobre a implementação de carregamento lento usando as ferramentas do navegador.

Hoje, chamamos a atenção para a tradução de um artigo no qual o uso da API IntersectionObserver é descrito usando uma página da Web simples como exemplo. Este material é destinado a programadores iniciantes.
O que é carregamento lento de imagens?
Ao analisar o desempenho do aplicativo, dois indicadores chegam à linha da frente - o tempo até a primeira interatividade (tempo para interatividade) e consumo de recursos (consumo de recursos). Eles inevitavelmente terão que enfrentar aqueles que estão envolvidos no desenvolvimento da web. Além disso, os problemas com os aplicativos podem surgir não apenas porque demoram muito tempo para se preparar para o trabalho ou consumir muitos recursos. Mas, em qualquer caso, é muito importante encontrar as fontes desses problemas o mais cedo possível e se esforçar para garantir que os problemas nem sequer surjam.
O uso de tecnologias de carregamento lento de imagens em aplicativos da Web minimiza o risco de problemas de desempenho. Ou seja, se analisarmos o carregamento lento do ponto de vista de sua influência no momento de colocar a página em condições de trabalho e consumo de recursos, obteremos o seguinte:
- Hora da primeira interatividade. Esse é o tempo que o aplicativo da web precisa carregar e colocar a interface em um estado adequado para o usuário trabalhar com ele. O carregamento lento (além disso, não se trata apenas de imagens) otimiza o tempo de resposta dos aplicativos, graças à tecnologia de separar código e carregar apenas o que uma página específica precisa ou o que é necessário em um determinado momento.
- Consumo de recursos. Os seres humanos são seres impacientes. Se um site precisar de mais de 3 segundos para carregar, 70% dos usuários deixam o site. Os aplicativos da Web não devem carregar por tanto tempo. O carregamento lento permite reduzir a quantidade de recursos necessários para o funcionamento das páginas. Por exemplo, isso pode significar que o código de um determinado projeto é dividido em fragmentos carregados apenas nas páginas que precisam deles. Como resultado, o desempenho do site aumenta e o consumo de recursos do sistema diminui.
Portanto, as tecnologias de carregamento lento aceleram os aplicativos, reduzindo o tempo de download e abertura. Isso é alcançado devido ao fato de que os recursos são carregados apenas quando são necessários.
Aqui estão algumas vantagens que o carregamento lento oferece a projetos da web:
- As páginas são carregadas mais rapidamente e ficam operacionais.
- No carregamento inicial das páginas, você precisa transferir e processar menos dados.
Carregamento lento de imagens usando a API IntersectionObserver
Se você pensar em como as páginas da Web são carregadas, fica claro que não faz sentido fazer o download de imagens ou outros recursos que não são visíveis para o usuário. Ao usar carregamento lento, as imagens que estão na área visível da página são carregadas primeiro. Em seguida, à medida que o usuário rola a página, outras imagens são carregadas e caem na área visível da página.
Considere um exemplo.
Página e sua área visívelVeja a figura anterior. Aqui você pode ver o navegador e a página da Web carregada nele. As imagens
#IMG_1
e
#IMG_2
estão no escopo da página. Isso significa que eles são visíveis ao usuário e estão dentro dos limites da área da janela do navegador exibida na tela.
Essa ordem de trabalho com a página não pode ser considerada ideal quando, quando carregada, as imagens
#IMG_1
,
#IMG_2
,
#IMG_3
e
#IMG_4
. Apenas
#IMG_1
e
#IMG_2
estão visíveis para o
#IMG_2
e
#IMG_3
e
#IMG_4
estão ocultos dele. Se você carregar a primeira e a segunda imagens enquanto carrega a página, mas não baixar as terceira e quarta imagens, isso poderá ter um impacto positivo no desempenho do site. Ou seja, estamos falando sobre o seguinte. Quando o usuário rola a página para que a terceira imagem fique visível, ela é carregada. Se a rolagem continuar e a quarta imagem ficar visível, ela também será carregada.
Rolar uma página e carregar imagensAgora que descobrimos exatamente como queremos trabalhar com imagens, nos perguntamos como descobrir que um determinado elemento de uma página cai em sua área visível. Navegadores modernos têm uma API que permite ao programador descobrir quando uma determinada área da página se torna visível. É sobre a API IntersectionObserver. Ele permite, usando mecanismos assíncronos, organizar o monitoramento de elementos e receber notificações nos casos em que um elemento cruza o escopo do documento ou cruza a borda de outro elemento.
Para configurar o carregamento lento de imagens, primeiro precisamos preparar um código de modelo para o elemento que será usado para descrever as imagens. Aqui está:
<img class="lzy_img" src="lazy_img.jpg" data-src="real_img.jpg" />
A classe permite identificar um elemento como uma imagem à qual o carregamento lento será aplicado. O atributo
src
permite exibir uma imagem de espaço reservado antes de exibir a imagem real.
data-src
armazena o endereço da imagem real, que será carregada quando o elemento entrar na área visível da página.
Agora vamos escrever o código que implementa o carregamento lento. Como já mencionado, usaremos a API IntersectionObserver para detectar o momento em que a imagem entra na área de visualização da página.
Primeiro, crie uma instância do
IntersectionObserver
:
const imageObserver = new IntersectionObserver(...);
O construtor
IntersectionObserver
aceita uma função com dois parâmetros. Um deles armazena uma matriz que consiste em elementos que precisam ser monitorados; o outro, uma instância
IntersectionObserver
. É assim:
const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => {
O código da função verifica se as imagens representadas pelas
entries
matriz de
entries
cruzam a janela de visualização. Se for esse o caso, o atributo
src
da imagem correspondente registra o que estava em seu atributo
data-src
.
const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => { if(entry.isIntersecting) { const lazyImage = entry.target lazyImage.src = lazyImage.dataset.src } }) });
Aqui, verificamos, usando a condição
if(entry.isIntersecting) {...}
, se o elemento cruza a área de visualização do navegador.
lazyImage
caso, salvamos o elemento
img
na constante
lazyImage
. Em seguida, escrevemos em seu atributo
src
que estava em seu atributo
data-src
. Graças a isso, a imagem cujo endereço está armazenado no
data-src
é carregada e exibida. No navegador, parece substituir a imagem do espaço reservado,
lazy_img.jpg
, por uma imagem real.
Agora precisamos usar o método
.observe()
da nossa instância
IntersectionObserver
para começar a monitorar os elementos de interesse para nós:
imageObserver.observe(document.querySelectorAll('img.lzy_img'));
Aqui, selecionamos todos os elementos
img
com a classe
lzy_img
no
document.querySelectorAll('img.lzy_img')
com o comando
document.querySelectorAll('img.lzy_img')
e os passamos para o método
.observe()
. Tendo recebido uma lista de elementos, ele inicia o processo de observá-los.
Para testar este exemplo, começamos inicializando o projeto Node.js.
mkdir lzy_img cd lzy_img npm init -y
Agora crie o arquivo
lzy_img
na pasta
lzy_img
:
touch index.html
Adicione o seguinte código a ele:
<html> <title>Lazy Load Images</title> <body> <div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_1.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_2.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_3.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_4.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_5.jpg" /> <hr /> </div> </div> <script> document.addEventListener("DOMContentLoaded", function() { const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => { if (entry.isIntersecting) { const lazyImage = entry.target console.log("lazy loading ", lazyImage) lazyImage.src = lazyImage.dataset.src } }) }); const arr = document.querySelectorAll('img.lzy_img') arr.forEach((v) => { imageObserver.observe(v); }) }) </script> </body> </html>
Você pode observar que 5 imagens são descritas aqui, nas quais o espaço reservado
lazy_img.jpg
é exibido ao carregar. O atributo
data-src
de cada um deles contém informações sobre imagens reais. Aqui está uma lista de nomes de imagens usados no projeto:
lazy_img.jpg img_1.jpg img_2.jpg img_3.jpg img_4.jpg img_5.jpg
Você precisa criar todas essas imagens trazendo a pasta do projeto para a exibição mostrada na figura a seguir.
Pasta do projetoNo meu caso, o arquivo
lazy_img.jpg
preparado usando o Windows Paint, e as imagens reais (
img_*.jpg
Jpg ) foram obtidas do
pixabay.com .
Observe que o retorno de chamada usado para criar a instância
IntersectionObserver
possui uma chamada
console.log()
. Isso nos permitirá aprender a executar operações para carregar imagens diferentes.
Agora, para veicular
index.html
, usamos o pacote
http-server
:
npm i http-server
Inclua a propriedade
start
na seção
scripts
do arquivo
package.json
:
"scripts": { "start": "http-server ./" }
Depois disso, execute o comando
npm run start
no terminal.
Agora abra o navegador e vá para o endereço
127.0.0.1:8080
. Nossa página
index.html
no início será semelhante à figura a seguir.
Página sem imagens reaisVocê pode perceber que onde as imagens reais deveriam estar, apenas os espaços reservados agora são exibidos. Aqui partimos do pressuposto de que a primeira imagem está na área de visualização, para que o navegador comece a baixá-la. Como resultado, a página ficará assim.
Navegador carregou a primeira imagemOutras imagens ainda não carregadas. Eles ainda não chegaram à área de visualização.
Se você rolar a página enquanto assiste ao console, notará um problema. Consiste no fato de que, ao rolar pela mesma imagem na janela de visualização, o navegador tenta fazer o download várias vezes.
Vários uploads da mesma imagemNão é disso que precisamos. Isso leva ao desperdício desnecessário de recursos do sistema e prejudica o desempenho do projeto.
Para resolver esse problema, precisamos remover o elemento
img
, cuja imagem real já está carregada, da lista de elementos que nossa instância
IntersectionObserver
está assistindo. Também precisamos remover a classe
lzy_img
desse elemento. Aqui está o que parece no código da função de retorno de chamada editada:
<script> document.addEventListener("DOMContentLoaded", function() { const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => { if (entry.isIntersecting) { const lazyImage = entry.target console.log("lazy loading ", lazyImage) lazyImage.src = lazyImage.dataset.src lazyImage.classList.remove("lzy_img"); imgObserver.unobserve(lazyImage); } }) }); const arr = document.querySelectorAll('img.lzy_img') arr.forEach((v) => { imageObserver.observe(v); }) }) </script>
Após carregar a imagem real do elemento
img
correspondente, sua classe
lzy_img
é
lzy_img
e o elemento é excluído da lista de elementos que
IntersectionObserver
está observando.
Aqui está o código de exemplo:
<html> <title>Lazy Load Images</title> <body> <div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_1.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_2.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_3.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_4.jpg" /> <hr /> </div> <div style=""> <img class="lzy_img" src="lazy_img.jpg" data-src="img_5.jpg" /> <hr /> </div> </div> <script> document.addEventListener("DOMContentLoaded", function() { const imageObserver = new IntersectionObserver((entries, imgObserver) => { entries.forEach((entry) => { if (entry.isIntersecting) { const lazyImage = entry.target console.log("lazy loading ", lazyImage) lazyImage.src = lazyImage.dataset.src lazyImage.classList.remove("lzy_img"); imgObserver.unobserve(lazyImage); } }) }); const arr = document.querySelectorAll('img.lzy_img') arr.forEach((v) => { imageObserver.observe(v); }) }) </script> </body> </html>
Sumário
Examinamos o exemplo mais simples da implementação do sistema de carregamento lento de imagens. Mas o IntersectionObserver permite criar esquemas de carregamento bastante complexos e preguiçosos. Se você estiver interessado neste tópico, recomendamos que você examine as publicações mencionadas no início do material e leia a
documentação .
Caros leitores! Você tem exemplos de como melhorar o desempenho do site após implementar um sistema lento de carregamento de imagens?
