Carga asíncrona en nuestras páginas
Tags: html, css, javascript, async
Published: 2020-05-30 21:12:36

Estamos buscando constantemente la forma correcta de crear sitios Web o aplicaciones Web y la manera como incluimos nuestros archivos nos puede dar una ayuda extra en ese proceso, y es el porque de este artículo, y compartirles que podemos tener en cuenta en este proceso.

Primero iniciemos por lo básico para aquellas personas que están en sus pequeños pasos (o baby steps en este mundo del desarrollo Web), y lo primero seria responder al gran interrogante ¿cómo construimos una página Web?

Para construir una página Web contamos con tres maravillosas herramientas que podemos ver en la imagen a continuación en una torta, tenemos el CSS (presentación), el HTML (contenido), y JavaScript (comportamientos o el toque especial).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7pwu8wnxh47h275l3w9t.png)

Para ampliar, aunque tenemos ahora miles de recursos para extender más el concepto de HTML, que es su definición más simple es un lenguaje de marcado de hipertexto, que esta formado de elementos que a su vez son etiquetas con las cuales damos significado a nuestro contenido y lo estructuramos. El CSS, que es una hoja de estilo en cascada nos permite manejar el formato de presentación de nuestro contenido (en términos simples, estilizarlo, darle mas forma y orden de cara al usuario). Finalmente el JS, al igual que los dos anteriores hay mucho de contenido sobre él, podemos decir en una definición pequeña que es un lenguaje de programación, débilmente tipado y dinámico, que nos permite dar vida a nuestro documento, nos permite modificar el estado de un componente, nos permite trabajar del lado del cliente y servidor.

Bueno ahora que ya sabemos que necesitamos para construir una página, surge otro gran interrogante y es: ¿Cómo se renderiza nuestro HTML, CSS y JS en un navegador?

Para hacer esto hay unos pasos que se realizan para ver el contenido que queremos mostrarle a nuestros usuarios:

1. Construcción del DOM (Document Object Model)

Nuestro HTML que esta compuesto por etiquetas, en este proceso es parseado, donde se toman cada uno de los caracteres de acuerdo al formato que podemos definir en nuestro head, luego en tokens donde se convierten en objetos, donde cada uno tendrá unas propiedades y reglas y como en nuestro documento cada etiqueta tiene una relación, los objetos se vinculan en una estructura de datos en forma de árbol.

En el siguiente ejemplo podemos ver como nuestro HTML se convierte en nuestro árbol de objetos (nodos)

Nuestro HTML:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/psw5a7fj39wh9rddtw6h.png)

Nuestro árbol o DOM:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/colyb4i38834nyaxylgt.png)

2. Construcción del CSSOM

Nuestro CSS esta compuesto de selectores, así que en este paso se hace un proceso similar al HTML, pero con el CSS, cuando se parsea el contenido del CSS, se toman cada uno de sus elementos y selectores y se convierten en objetos, estos objetos tienen unas propiedades y reglas y se representan en un árbol.


Nuestra hoja de estilos (CSS)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ph0tvbpgh2w58wiibx5y.png)

Nuestro árbol o CSSOM
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/afmivvtnfu126wv4m9zg.png)

3. Ejecuta el JavaScript

En este paso se ejecutan nuestros scripts (un script lo podemos definir como una lista de órdenes). En nuestro HTML mediante la etiqueta script especificamos si queremos añadir nuestro script en línea o de un archivo externo.

script en línea
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/k01l5yfsrvyzzr5g2iwl.png)

script externo
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6yjisl9ylnunqyik6wju.png)

4. Se crea el árbol de renderizado

En este paso se fusionan los dos árboles anteriores, y se calcula el diseño de cada elemento que será visible en nuestra página. Cuando inspeccionamos nuestra página con el DevTools este es el árbol que vemos.

Render Tree o árbol de renderizado
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/uwsgw1fy45yljllm2qu3.png)

5. Estructuras y pintar

En este último paso se genera el Layout y se pinta en nuestra página nuestro Mockup. El contenido se convierte a píxeles para ser reflejados en una pantalla.

Se estructura y pinta el contenido
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/m26b7lo8ujzl2i6s79qi.png)

Hasta ahora hemos hablado de como mostramos nuestro HTML, CSS y JS, pero no hemos hablado del tema que compete a este articulo que es la carga asíncrona. Pero lo que quiero que entiendas es que lo anterior nos lleva nuestro tema es cuestión, aunque hay un tema más del que quiero darte una pequeña introducción y es sobre la carga síncrona.

¿Qué es la carga síncrona?

Cuando un navegador carga una página, va parseando el contenido del HTML, lo que ya mencionamos anteriormente. Cada vez que incluimos un script, se carga de forma síncrona, quiere decir secuencial y, por tanto, debemos esperar a que se complete para procesar el resultado.

Entonces cuando estamos en el proceso de renderizado de nuestra página y se llega a un script, el navegador detiene la lectura y procesamiento del HTML, hasta que el navegador descarga el archivo y lo ejecuta.

Una vez se termina este proceso, se podrá dar continuidad a la carga de la página.

Esto puede tener un efecto muy negativo de cara al usuario.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7i80qi9nijvjt931iycx.png)

Si tomaras un caso de la vida real, una Web que ofrece una respuesta lenta al usuario tiene un efecto tan negativo como cuando alguien se declara y cuando de pronto hay una pausa incómoda prolonga más de 7 segundos.
Ups… Houston, ¡tenemos un problema!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6o72ypblesheb7lmik9l.png)

Ese problema de carga lenta nos lleva a la gran pregunta ¿debe ir el script en el body?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/c0c4mx5wo9medtgrhnrq.png)

Dando respuesta a esa pregunta, nos lleva a la buena práctica que hemos dicho por años: el JavaScript ha de ir lo más abajo posible. Es muy importante que la evaluación del script se haga tan pronto como en el parseo se encuentre con la etiqueta script, así que es preferible tener cargada la mayor parte del DOM antes de ponernos a interactuar con él. Por eso siempre nos decían que era buena práctica incluir nuestros scripts al final.

¿Qué es la carga asíncrona?

Por fin el tema que nos compete, cuando decimos que algo sea asíncrono, en otras palabras queremos que múltiples cosas pasen al mismo tiempo. Que al iniciar una acción, el programa continué ejecutándose.

Entonces para hacer uso de este termino en nuestro HTML, tenemos la opción de incluir un atributo llamado “async”, que es un booleano y que le indica a nuestro script que puede ser ejecutado asíncronamente. Aunque este atributo solo puede aplicado para scripts externos (en otros términos cuando tenemos en la etiqueta script el atributo src presente).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y7r8t3x5y8unlmvgx0j8.png)

El atributo async, como mencione, permite que un script externo sea ejecutado inmediatamente pero de forma asíncrona, dejando que el parser siga analizando el documento sin esperar a que la ejecución del script finalice, por lo que para este caso podemos añadir nuestro script en el head de nuestro HTML. En el paso de ejecución el código JavaScript se descargara de forma paralela, sin detener la carga de la página, y se ejecutará nada más estar disponible.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3l5sv2203153l0s3r2wa.png)

Este atributo permite la eliminación de lo que se conoce como el parser-blocking (bloquean el análisis y renderizado) de JS donde el navegador tendría que cargar y evaluar los scripts antes de continuar con el análisis.

Existe otro atributo en nuestro HTML que tiene un efecto similar y es el defer.

Como mencione antes de la buena práctica, esa era una de las primeras recomendaciones que solíamos hacer para evitar ese bloqueo. De esta forma, cuando se parseaba el HTML y se encontraba un script, casi todo el documento ya se había analizado y renderizado.

Aunque aun sigue existiendo un bloqueo en el renderizado pero menor y bueno hacemos uso de un componente visual que llamamos spinner o en sus diferentes versiones visuales el loading.

Algo que debemos tener en cuenta es que aunque añadamos el atributo async, con este no se garantiza la ejecución de los scripts asíncronos en el mismo orden en el aparecen en el documento.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4h7tcm4ri0ofsvfn1bp4.png)

Dando un poco más detalle del atributo defer, con este el script se descarga de forma asíncrona, en paralelo con el análisis HTML, y además su ejecución es diferida hasta que termine el análisis HTML. No hay bloqueo en el renderizado HTML. La ejecución de todos los scripts diferidos se realiza en el mismo orden en el que aparecen en el documento, esta es una de las ventajas del uso de este atributo.

Haciendo un análisis de un documento que tiene un script con o sin los atributos mencionados, podemos ver lo siguiente:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/o4cowjn2m8be268iijnt.png)

En la gráfica podemos ver que pasa en el proceso de descarga y ejecución del script y como es afectado el análisis del HTML.

¿Cuando utilizar cada uno?

“async” y “defer” son ideales para scripts que manipulan o interactúan con el DOM antes del DOMContentLoaded. El evento DOMContentLoaded es disparado cuando el documento HTML ha sido completamente cargado y parseado, sin esperar hojas de estilo, imágenes y sub-frames para finalizar la carga.

El “async” es bueno cuando no se tienen dependencias con otros scripts.

El “defer”, sería una buena opción si el script tiene dependencias con otros scripts y es importante el orden en el que se ejecuta cada uno.
Aunque existen las dos opciones anteriores, no se puede dejar de lado la forma tradicional y los scripts inline, son buenos usarlos pero en el caso de un script pequeño. Si el script es pequeño, el análisis HTML se detendría pero sería una interferencia muy pequeña en comparación con la solicitud y descarga del archivo.

Podemos hacernos las siguientes preguntas para implementar el script con atributo o sin él.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lj9tjsl77aveyowxchaq.png)

En el caso del script pequeño y si otros asíncronos dependen de él, entonces se puede colocar el script en línea sin ninguno atributo justo encima de los scripts asíncronos.

Conclusión

Podemos hacer la carga asíncrona de nuestra página haciendo uso de atributos como el async y el defer, dependiendo del caso de uso, aunque es bueno recordar que solo aplica para archivos externos. Es bien sabido que en la actualidad hacemos uso de Frameworks y librerías en la construcción de nuestras aplicaciones Web y podemos hacer uso de los anteriores atributos como mencione dependiendo de como estemos construyendo nuestra aplicación. Lo anterior nos ayuda mucho a optimizar la carga de nuestra página aunque no debemos olvidar algunos tips como:

1. Controlar las carga del CSS & JS, ordenar su carga no reducirá el tiempo total pero ayuda la experiencia. Podemos agrupar todos los links de nuestras diferentes hojas de estilo en una sola (usar link en lugar de import para CSS externo), al igual que nuestros scripts.

2. Unificar las imágenes. Se pueden unificar todas las imágenes en una única tira, y acceder mediante sprites para cargar diferentes secciones de la tira en cada uno de los espacios en los que queremos mostrar las imágenes.

3. Lazy-loading en imágenes. Implementar el atributo loading dentro del tag img de HTML. El atributo loading permite al navegador retrasar la carga de imágenes y de iframes que están fuera de pantalla, hasta que el usuario haga scroll cerca de ellas.

4. Excluir componentes no usados de las librerías. Hay algunas que incluyen más archivos de los que necesitamos. Si existe la manera de administrar qué componentes se incluirán, es bueno remover todo lo que no necesitemos, así nuestra página se cargará mucho más rápido y nuestros usuarios tendrán una mejor experiencia.