Scripts Async, Defer
Scripts Async, Defer
ES
12 de julio de 2022
Cuando el navegador carga el HTML y se encuentra con una etiqueta <script>...</script> , no puede
continuar construyendo el DOM. Debe ejecutar el script en el momento. Lo mismo sucede con los scripts
externos <script src="..."></script> , el navegador tiene que esperar hasta que el script sea
descargado, ejecutarlo y solo después procesa el resto de la página.
1. Los scripts no pueden ver los elementos del DOM que se encuentran debajo de él por lo que no pueden
agregar controladores de eventos, etc.
2. Si hay un script muy pesado en la parte superior de la página, este “bloquea la página”. Los usuarios no
pueden ver el contenido de la página hasta que sea descargado y ejecutado.
1 <p>...contenido previo al script...</p>
2
3 <script src="https://javascript.info/article/script-async-defer/long.js?spee
4
5 <!-- Esto no es visible hasta que el script sea cargado -->
6 <p>...contenido posterior al script...</p>
Hay algunas soluciones para eso. Por ejemplo podemos poner el script en la parte inferior de la página por lo
que podrá ver los elementos sobre él y no bloqueará la visualización del contenido de la página.
1 <body>
2 ...todo el contenido está arriba del script...
3
4 <script src="https://javascript.info/article/script-async-defer/long.js?sp
5 </body>
Pero esta solución está lejos de ser perfecta. Por ejemplo el navegador solo se dará cuenta del script (y
podrá empezar a descargarlo) después de descargar todo el documento HTML. Para documentos HTML
extensos eso puede ser un retraso notable.
Este tipo de cosas son imperceptibles para las personas que usan conexiones muy rápidas, pero muchas
personas en el mundo todavía tienen velocidades de internet lentas y utilizan una conexión de internet móvil
que esta lejos de ser perfecta.
Afortunadamente hay dos atributos de <script> que resuelven ese problema para nosotros: defer y
async .
defer
El atributo defer indica al navegador que no espere por el script. En lugar de ello, debe seguir procesando
el HTML, construir el DOM. El script carga “en segundo plano” y se ejecuta cuando el DOM esta completo.
1 <p>...contenido previo script...</p>
2
3 <script defer src="https://javascript.info/article/script-async-defer/long.j
4
5 <!-- Inmediatamete visible -->
6 <p>...contenido posterior al script...</p>
En otras palabras:
1 <p>...contenido previo a los scripts...</p>
2
3 <script>
4 document.addEventListener('DOMContentLoaded', () => alert("¡DOM listo desp
5 </script>
6
7 <script defer src="https://javascript.info/article/script-async-defer/long.j
8
9 <p>...contenido posterior a los scripts...</p>
**Los scripts diferidos mantienen su orden relativo, tal cual los scripts regulares.
Digamos que tenemos dos scripts diferidos, long.js (largo) y luego small.js (corto):
1 <script defer src="https://javascript.info/article/script-async-defer/long.j
2 <script defer src="https://javascript.info/article/script-async-defer/small.
Los navegadores analizan la página en busca de scripts y los descarga en paralelo para mejorar el
rendimiento. Entonces en el ejemplo superior ambos scripts se descargan en paralelo, el small.js
probablemente lo haga primero.
…Pero el atributo defer , además de decirle al navegador “no bloquear”, asegura que el orden relativo se
mantenga. Entonces incluso si small.js se carga primero, aún espera y se ejecuta después de
long.js .
Por ello es importante para casos donde necesitamos cargar un librería JavaScript y entonces un script que
depende de ella.
async
El atributo async es de alguna manera como defer . También hace el script no bloqueante. Pero tiene
importantes diferencias de comportamiento.
En otras palabras, los scripts async cargan en segundo plano y se ejecutan cuando están listos. El DOM y
otros scripts no esperan por ellos, y ellos no esperan por nada. Un script totalmente independiente que se
ejecuta en cuanto se ha cargado. Tan simple como es posible, ¿cierto?
Aquí hay un ejemplo similar al que vimos con defer : Dos scripts long.js y small.js , pero ahora con
async en lugar de defer .
Los unos no esperan por lo otros. El que cargue primero (probablemente small.js ), se ejecuta primero.
1 <p>...contenido previo a los scripts...</p>
2
3 <script>
4 document.addEventListener('DOMContentLoaded', () => alert("¡DOM listo!"
5 </script>
6
7 <script async src="https://javascript.info/article/script-async-defer/long.j
8 <script async src="https://javascript.info/article/script-async-defer/small.
9
10 <p>...contenido posterior a los scripts...</p>
Los scripts asincrónicos son excelentes cuando incluimos scripts de terceros (contadores, anuncios, etc) en
la página debido a que ellos no dependen de nuestros scripts y nuestros scripts no deberían esperar por
ellos.
Scripts dinámicos
Hay otra manera importante de agregar un script a la página.
1 let script = document.createElement('script');
2 script.src = "/article/script-async-defer/long.js";
3 document.body.append(script); // (*)
Esto es:
Esto puede ser cambiado si explícitamente establecemos script.async=false . Así los scripts serán
ejecutados en el orden del documento, tal como en defer .
En este ejemplo, la función loadScript(src) añade un script y también establece async a false .
Entonces long.js siempre ejecuta primero (por haber sido agregado primero):
1 function loadScript(src) {
2 let script = document.createElement('script');
3 script.src = src;
4 script.async = false;
5 document.body.append(script);
6 }
7
8 // long.js se ejecuta primero a causa del async=false
9 loadScript("/article/script-async-defer/long.js");
10 loadScript("/article/script-async-defer/small.js");
De nuevo, como con defer , el orden importa si queremos cargar una librería y luego otro script que
depende de ella.
Resumen
Ambos, async y defer , tienen algo en común: la descarga de tales scripts no bloquean el renderizado de
la página. Por lo cual el usuario puede leer el contenido de la página y familiarizarse con la página
inmediatamente.
Orden DOMContentLoaded
Document order (como van en Ejecutan después de que el documento es cargado y analizado
defer
el documento). (espera si es necesario), justo antes de DOMContentLoaded .
En la práctica, defer es usado para scripts que necesitan todo el DOM y/o si su orden de ejecución relativa
es importante.
Y async es usado para scripts independientes, como contadores y anuncios donde el orden de ejecución
no importa.
La página sin scripts debe ser utilizable
Ten en cuenta: si usas defer o async , el usuario verá la página antes de que el script sea cargado.
No olvides poner alguna señal de “cargando” y deshabilitar los botones que aún no estén funcionando.
Esto permite al usuario ver claramente qué puede hacer en la página y qué está listo y qué no.
Comentarios
● Si tiene sugerencias sobre qué mejorar, por favor enviar una propuesta de GitHub o una solicitud
de extracción en lugar de comentar.
● Si no puede entender algo en el artículo, por favor explique.
● Para insertar algunas palabras de código, use la etiqueta <code> , para varias líneas –
envolverlas en la etiqueta <pre> , para más de 10 líneas – utilice una entorno controlado
(sandbox) (plnkr, jsbin, codepen…)