Atualmente, o principal obstáculo no caminho para locais de carregamento de alta velocidade são as imagens. Isto é especialmente verdade para projetos de comércio eletrônico. As imagens nelas, geralmente bastante "pesadas", compõem a maior parte do conteúdo das páginas. Como regra, isso leva ao fato de que, para mostrar ao usuário uma página, seu navegador precisa baixar vários megabytes de dados gráficos. Como acelerar o carregamento da página nesta situação? A resposta a esta pergunta é dedicada ao material, cuja tradução publicamos hoje.

Disposições Gerais
Considere, por exemplo, a página
inicial do departamento de
Casa do Walmart.
Uma página com muitas imagensAqui estão as informações sobre quantas imagens são carregadas para formar esta página:
Imagens carregadas durante a formação da páginaComo você pode ver, existem 137 imagens! Isso significa que mais de 80% dos dados necessários para exibir a página e transmitidos pela rede são apresentados como arquivos gráficos.
Agora analisamos as solicitações de rede que são executadas quando a página é carregada:
Solicitações de rede executadas durante a formação da páginaNesse caso, os arquivos resultantes da separação do código do projeto são baixados mais tarde do que podiam. Isso ocorre porque você primeiro precisa carregar o pacote principal
cp_ny.bundle
. O download deste pacote poderia ser muito mais rápido se não fosse perturbado por 18 imagens que competem entre si por largura de banda.
Como consertar isso? De fato, para realmente "consertar" isso não funcionará, mas você pode fazer muitas coisas para otimizar o carregamento da imagem. Existem muitas abordagens para otimizar imagens usadas em páginas da web. Entre eles estão o uso de vários formatos de arquivo gráfico, compactação de dados, o uso da técnica de animação de desfoque, o uso da CDN. Gostaria de me debruçar sobre o chamado "carregamento lento" de imagens (carregamento lento). Em particular, falaremos sobre como implementar essa técnica nos sites React, mas como é baseada em mecanismos JavaScript, ela pode ser integrada a qualquer projeto da web.
Projeto piloto
Vamos começar com um componente extremamente simples do
Image
React:
class Image extends PureComponent { render() { const { src } = this.props; return <img align="center" src={src} />; } }
Ele pega como propriedade uma URL e a usa para renderizar o elemento HTML
img
.
Aqui está o código JSFiddle relevante. A imagem a seguir mostra a página que contém este componente. Observe que, para ver a imagem exibida por ele, você precisa rolar o conteúdo da página.
A página com o componente que exibe a imagemPara implementar a técnica de carregamento lento de imagens neste componente, você precisa executar as três etapas a seguir:
- Não renderize a imagem imediatamente após o download.
- Configure ferramentas para detectar a aparência de uma imagem na área de visualização do conteúdo da página.
- Exiba a imagem depois que for detectado que caiu na área de visualização.
Vamos dar uma olhada nessas etapas.
Etapa 1
Nesta etapa, a imagem imediatamente após o carregamento não é exibida.
render() { return <img />; }
Etapa 2
Aqui, configuramos os mecanismos que permitem detectar o momento em que a imagem entra na área de visualização.
componentDidMount() { this.observer = new IntersectionObserver(() => { // }, { root: document.querySelector(".container") }); this.observer.observe(this.element); } .... render() { return <img ref={el => this.element = el} />; }
Vamos analisar esse código. Aqui está o que foi feito aqui:
- O atributo ref foi adicionado ao elemento
img
. Isso permite que você atualize posteriormente o link da imagem no src
sem precisar renderizar novamente o componente. - Uma nova instância do
IntersectionObserver
(falaremos sobre isso abaixo). - O objeto
IntersectionObserver
é solicitado a observar a imagem usando a construção observe(this.element)
.
O que é o
IntersectionObserver
? Considerando que a palavra “interseção” é traduzida como “interseção” e “observador” é “observador”, já é possível adivinhar o papel desse objeto. Se você procurar informações sobre isso no
MDN , poderá descobrir que a API Intersection Observer permite que aplicativos da Web monitorem de forma assíncrona as alterações na interseção de um elemento com seu pai ou no escopo de um documento de viewport.
À primeira vista, essa característica da API pode não parecer particularmente compreensível, mas, na verdade, é muito simples em sua estrutura. A instância
IntersectionObserver
recebe vários parâmetros. Em particular, usamos o parâmetro
root
, que permite definir o elemento DOM raiz, que consideramos um contêiner, sobre a interseção do elemento com a borda da qual precisamos conhecer. Por padrão, essa é a área na qual o fragmento visível da página (viewport) está localizado, mas eu o configurei explicitamente para usar o contêiner localizado no elemento
iframe
do JSFiddle. Isso é feito para, posteriormente, considerar uma possibilidade que não foi projetada para usar elementos
iframe
.
O motivo pelo qual o
IntersectionObserver
para determinar quando um item se torna visível é mais popular do que os métodos tradicionais, como o
onScroll
e o
getBoundingClientRect()
juntos, porque os mecanismos do
IntersectionObserver
executados fora do encadeamento principal. No entanto, o retorno de chamada chamado após
IntersectionObserver
detecta que a interseção do elemento com o contêiner é executada naturalmente no thread principal, portanto, seu código não deve ser muito pesado.
Etapa 3
Agora precisamos configurar o retorno de chamada que é chamado quando ele detecta a interseção do elemento de
target
(
this.element
no nosso caso) com o contêiner
root
(no nosso caso, é um elemento
div
.container
).
.... this.observer = new IntersectionObserver( entries => { entries.forEach(entry => { const { isIntersecting } = entry; if (isIntersecting) { this.element.src = this.props.src; this.observer = this.observer.disconnect(); } }); }, { root: document.querySelector(".container") } ); ....
Quando a interseção é detectada, a matriz de
entries
transferida para o
entries
, que se assemelha a um conjunto de capturas instantâneas do status de todos os elementos de destino para os quais a interseção da borda especificada foi detectada. A propriedade
isIntersecting
indica a direção da interseção. Se o item que está sendo monitorado estiver fora do elemento raiz, é
true
. Se um elemento sai do elemento raiz, é
false
.
Portanto, quando o elemento cruza a borda inferior do contêiner, defino manualmente sua propriedade
src
e desativo o monitoramento, o que não é mais necessário.
Etapa 4 (secreta)
Agora, na quarta etapa secreta do nosso trabalho, você pode admirar o resultado e obter sucesso. Aqui está o
código que coleta o que acabamos de falar.
O resultado da aplicação da técnica de carregamento lento de imagensNo entanto, se você olhar mais de perto o que temos, acontece que aqui você pode encontrar algo não muito bom. Para ver isso, rolei a página rapidamente, diminuindo a velocidade da conexão de rede.
Comportamento da página quando rola rapidamente e diminui a velocidade da conexão de redeComo carregamos uma imagem somente depois que ela atingiu a área em que já deveria estar visível, o usuário não tem a oportunidade de rolar a página e ver a área ocupada pela imagem e, é claro, a própria imagem antes de carregá-la. Quando sites olham de computadores comuns conectados à Internet rápida, isso não causa problemas. Mas muitos usuários modernos visitam sites de seus telefones, às vezes usam redes 3G ou, pior ainda, conexões EDGE.
É verdade que lidar com esse problema não é tão difícil. Isso pode ser feito devido ao fato de a API Intersection Observer fornecer ao desenvolvedor a capacidade de expandir ou restringir os limites do elemento raiz (no nosso caso, esse é o elemento
.container
). Para usar esta oportunidade, basta adicionar uma linha de código no local em que o contêiner raiz está configurado:
rootMargin: "0px 0px 200px 0px"
Na propriedade
rootMargin
, escreva uma linha cuja estrutura esteja em conformidade com as regras CSS usadas para configurar o recuo dos elementos. No nosso caso, informamos ao sistema que a borda inferior usada para detectar a interseção de um elemento com um contêiner precisa ser aumentada em 200 pixels. Isso significa que o retorno de chamada correspondente será chamado quando o elemento cair em uma área 200 pixels abaixo da borda inferior do elemento raiz (o valor padrão é 0).
Aqui está o código que implementa essa técnica.
Melhorando a técnica de carregamento lento de imagensComo resultado, acontece que, quando rolamos a página apenas para o quarto elemento da lista, a imagem é carregada em uma área que fica 200 pixels abaixo da área visível da página.
Agora, ao que parece, tudo o que é necessário está feito. Mas isso não é verdade.
Problema na altura da imagem
Se você estudou cuidadosamente as ilustrações GIF acima, poderá perceber que a barra de rolagem faz um "pulo" depois de carregar a imagem. Felizmente, esse problema é fácil de lidar. Seu motivo é que o elemento que exibe a imagem inicialmente tem uma altura de 0, que, após carregar a imagem, tem 300 pixels. Portanto, para corrigir o problema, basta definir o elemento para uma altura fixa adicionando o atributo
height={300}
à imagem.
Sobre os resultados da otimização
Que resultados alcançamos no Walmart após aplicar o carregamento lento de imagens
nesta página? De fato, os resultados específicos variam muito, dependendo de muitas circunstâncias, entre as quais podemos observar a velocidade da conexão de rede do cliente, a disponibilidade da CDN, o número de imagens na página e as regras para detectar interseções com o elemento raiz aplicado a elas. Em outras palavras, para você, para avaliar o impacto do carregamento lento de imagens em seu próprio projeto, é melhor implementar e verificar isso sozinho. Mas se você ainda estiver interessado em ver o que o carregamento lento de imagens nos deu, aqui estão alguns relatórios do Lighthouse. O primeiro é formado antes da otimização, o segundo - depois.
Relatório farol gerado antes da otimizaçãoRelatório farol gerado após otimizaçãoSumário
Hoje analisamos uma técnica para otimizar páginas da web usando o carregamento lento de imagens. Se as páginas do seu site estiverem cheias de imagens, possivelmente essa técnica será útil para você.
Caros leitores! Como você otimiza as imagens e o carregamento delas?