API IntersectionObserver e carregamento lento da imagem

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:

  1. 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.
  2. 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ível

Veja 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 imagens

Agora 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 projeto

No 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 reais

Você 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 imagem

Outras 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 imagem

Nã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?

Source: https://habr.com/ru/post/pt453586/


All Articles