Hoy en día, el principal obstáculo en el camino hacia los sitios de carga de alta velocidad son las imágenes. Esto es especialmente cierto para proyectos de comercio electrónico. Las imágenes en ellos, generalmente bastante "pesadas", constituyen la mayor parte del contenido de las páginas. Esto, como regla, lleva al hecho de que para mostrar una página al usuario, su navegador necesita descargar varios megabytes de datos gráficos. ¿Cómo acelerar la carga de la página en esta situación? La respuesta a esta pregunta está dedicada al material, cuya traducción publicamos hoy.

Disposiciones generales
Considere, por ejemplo, la página de
inicio del departamento de
Inicio en Walmart.
Una página con muchas imágenes.Aquí hay información sobre cuántas imágenes se cargan para formar esta página:
Imágenes cargadas durante la formación de la páginaComo puede ver, ¡hay 137 imágenes! Esto significa que más del 80% de los datos necesarios para mostrar la página y transmitidos a través de la red se presentan como archivos gráficos.
Ahora analizamos las solicitudes de red que se ejecutan cuando se carga la página:
Solicitudes de red ejecutadas durante la formación de la páginaEn este caso, los archivos resultantes de la separación del código del proyecto se descargan más tarde de lo que podrían. Esto se debe al hecho de que primero necesita cargar el paquete principal
cp_ny.bundle
. Este paquete podría descargarse mucho más rápido si no hubiera sido molestado por 18 imágenes que compiten entre sí por el ancho de banda.
¿Cómo arreglarlo? De hecho, para realmente "arreglar" esto no funcionará, pero puede hacer muchas cosas para optimizar la carga de imágenes. Existen muchos enfoques para optimizar las imágenes utilizadas en las páginas web. Entre ellos están el uso de varios formatos de archivos gráficos, la compresión de datos, el uso de la técnica de animación borrosa, el uso de CDN. Me gustaría detenerme en la llamada "carga diferida" de imágenes (carga diferida). En particular, hablaremos sobre cómo implementar esta técnica en los sitios React, pero como se basa en mecanismos de JavaScript, puede integrarse en cualquier proyecto web.
Proyecto piloto
Comencemos con un componente
Image
React tan extremadamente simple:
class Image extends PureComponent { render() { const { src } = this.props; return <img align="center" src={src} />; } }
Toma, como propiedad, una URL, y la usa para representar el elemento HTML
img
.
Aquí está el código JSFiddle relevante. La siguiente imagen muestra la página que contiene este componente. Tenga en cuenta que para ver la imagen mostrada por él, debe desplazarse por el contenido de la página.
La página con el componente que muestra la imagen.Para implementar la técnica de carga diferida de imágenes en este componente, debe realizar los siguientes tres pasos:
- No renderice la imagen inmediatamente después de la descarga.
- Configure herramientas para detectar la apariencia de una imagen en el área de visualización del contenido de la página
- Muestre la imagen después de detectar que cayó en el área de visualización.
Echemos un vistazo a estos pasos.
Paso 1
En este paso, no se muestra la imagen inmediatamente después de la carga.
render() { return <img />; }
Paso 2
Aquí configuramos los mecanismos que nos permiten detectar el momento en que la imagen ingresa al área de visualización.
componentDidMount() { this.observer = new IntersectionObserver(() => { // }, { root: document.querySelector(".container") }); this.observer.observe(this.element); } .... render() { return <img ref={el => this.element = el} />; }
Analicemos este código. Esto es lo que se ha hecho aquí:
- El atributo ref se ha agregado al elemento
img
. Esto le permite actualizar más tarde el enlace de la imagen en src
sin tener que volver a representar el componente. - Se
IntersectionObserver
una nueva instancia de IntersectionObserver
(hablaremos de esto a continuación). - Se le solicita al objeto
IntersectionObserver
que observe la imagen utilizando la construcción observe(this.element)
.
¿Qué es
IntersectionObserver
? Teniendo en cuenta que la palabra "intersección" se traduce como "intersección" y "observador" es "observador", ya se puede adivinar el papel de este objeto. Si busca información al respecto en
MDN , puede descubrir que la API Intersection Observer permite a las aplicaciones web monitorear asincrónicamente los cambios en la intersección de un elemento con su elemento primario o el alcance de un documento de ventana gráfica.
A primera vista, esta característica de la API puede no parecer particularmente comprensible, pero, de hecho, es muy simple en estructura. La instancia de
IntersectionObserver
pasa varios parámetros. En particular, utilizamos el parámetro
root
, que nos permite establecer el elemento DOM raíz, que consideramos como un contenedor, acerca de la intersección del elemento con el borde que necesitamos conocer. De forma predeterminada, esta es el área en la que se encuentra el fragmento visible de la página (ventana gráfica), pero lo configuré explícitamente para usar el contenedor ubicado en el elemento
iframe
del JSFiddle. Esto se hace para, más adelante, considerar una posibilidad que no está diseñada para usar elementos de
iframe
.
La razón por la que usar
IntersectionObserver
para determinar cuándo un elemento se hace visible es más popular que los métodos más tradicionales, como el uso de
onScroll
y
getBoundingClientRect()
juntos, porque los mecanismos de
IntersectionObserver
se ejecutan fuera del hilo principal. Sin embargo, la devolución de llamada llamada después de que
IntersectionObserver
detecta la intersección del elemento con el contenedor se ejecuta naturalmente en el hilo principal, por lo que su código no debe ser demasiado pesado.
Paso 3
Ahora necesitamos configurar la devolución de llamada que se llama cuando detecta la intersección del elemento de
target
(este elemento en nuestro caso) con el contenedor
root
(en nuestro caso, es un 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") } ); ....
Cuando se detecta la intersección, la matriz de
entries
transfiere a la
entries
, que se asemeja a un conjunto de instantáneas del estado de todos los elementos de destino para los que se detecta la intersección del borde especificado. La propiedad
isIntersecting
indica la dirección de la intersección. Si el elemento que se está supervisando queda fuera del elemento raíz, es
true
. Si un elemento abandona el elemento raíz, entonces es
false
.
Entonces, cuando resulta que el elemento se ha cruzado con el borde inferior del contenedor, configuro manualmente su propiedad
src
y apago el monitoreo, lo que ya no es necesario.
Paso 4 (secreto)
Ahora, en el cuarto paso secreto de nuestro trabajo, puede admirar el resultado y disfrutar del éxito. Aquí está el
código que recopila lo que acabamos de hablar.
El resultado de aplicar la técnica de carga de imágenes diferidasSin embargo, si observa más de cerca lo que tenemos, resulta que aquí puede encontrar algo no muy bueno. Para ver esto, me desplacé rápidamente por la página, mientras disminuía la velocidad de la conexión de red.
Comportamiento de la página cuando se desplaza rápidamente y ralentiza la velocidad de conexión de redDado que cargamos una imagen solo después de que ha alcanzado el área en la que ya debería estar visible, el usuario no tiene la oportunidad de desplazarse por la página y ver el área ocupada por la imagen y, por supuesto, la imagen misma, antes de cargarla. Cuando los sitios miran desde computadoras comunes conectadas a Internet rápido, esto no causa problemas. Pero muchos usuarios modernos visitan sitios desde sus teléfonos, a veces usan redes 3G o, peor aún, conexiones EDGE.
Es cierto que lidiar con este problema no es tan difícil. Esto se puede hacer debido al hecho de que la API Intersection Observer proporciona al desarrollador la capacidad de expandir o estrechar los límites del elemento raíz (en nuestro caso, este es el elemento
.container
). Para aprovechar esta oportunidad, simplemente agregue una línea de código donde está configurado el contenedor raíz:
rootMargin: "0px 0px 200px 0px"
En la propiedad
rootMargin
, escriba una línea cuya estructura cumpla con las reglas CSS utilizadas para configurar la sangría de elementos. En nuestro caso, informamos al sistema que el borde inferior utilizado para detectar la intersección de un elemento con un contenedor debe aumentarse en 200 píxeles. Esto significa que se llamará a la devolución de llamada correspondiente cuando el elemento caiga en un área que esté 200 píxeles debajo del borde inferior del elemento raíz (el valor predeterminado es 0).
Aquí está el código que implementa esta técnica.
Mejorando la técnica de carga perezosa de imágenesComo resultado, resulta que cuando desplazamos la página solo al cuarto elemento de la lista, la imagen se carga en un área que está 200 píxeles debajo del área visible de la página.
Ahora, parece que todo lo que se necesita está hecho. Pero esto no es así.
Problema de altura de imagen
Si estudiaste cuidadosamente las ilustraciones GIF anteriores, entonces podrías notar que la barra de desplazamiento hace un "salto" después de cargar la imagen. Afortunadamente, este problema es fácil de manejar. Su razón es que el elemento que muestra la imagen inicialmente tiene una altura de 0, que, después de cargar la imagen, resulta ser de 300 píxeles. Por lo tanto, para solucionar el problema, es suficiente establecer el elemento en una altura fija agregando el atributo
height={300}
a la imagen.
Sobre los resultados de optimización
¿Qué resultados obtuvimos en Walmart después de aplicar la carga diferida de imágenes en
esta página? De hecho, los resultados específicos varían mucho dependiendo de muchas circunstancias, entre las cuales podemos observar la velocidad de conexión de red del cliente, la disponibilidad de CDN, el número de imágenes en la página y las reglas para detectar intersecciones con el elemento raíz aplicado a ellas. En otras palabras, para usted, para evaluar el impacto de la carga diferida de imágenes en su propio proyecto, es mejor implementarlo y verificarlo usted mismo. Pero si todavía está interesado en ver qué carga perezosa de imágenes nos dio, aquí hay un par de informes de Lighthouse. El primero se forma antes de la optimización, el segundo después.
Informe de faro generado antes de la optimizaciónInforme del faro generado después de la optimizaciónResumen
Hoy analizamos una técnica para optimizar las páginas web mediante la carga de imágenes diferidas. Si las páginas de su sitio están llenas de imágenes, entonces, posiblemente, esta técnica le será útil.
Estimados lectores! ¿Cómo optimizas las imágenes y su carga?