W3docs

Scripts: async, defer

En el desarrollo web moderno, la eficiencia de carga de páginas es clave. Los atributos async y defer controlan cómo se carga JavaScript.

El lugar donde colocas un <script> y cómo lo cargas influye directamente en la velocidad con que tu página se vuelve utilizable. Por defecto, los scripts pueden detener el navegador a mitad del renderizado; los atributos async y defer te permiten indicarle al navegador que descargue JavaScript en segundo plano. Este artículo explica cómo se comportan los scripts de bloqueo ordinarios, qué cambian async y defer, por qué los scripts de módulo se difieren automáticamente y cómo elegir la opción correcta para cada script.

Cómo un script normal bloquea el análisis

Un <script> sin async ni defer es bloqueante del renderizado. Cuando el analizador HTML llega a la etiqueta, deja de construir la página, descarga el script (si tiene un src), lo ejecuta hasta el final y solo entonces reanuda el análisis del resto del documento:

<p>...content before script...</p>

<script src="big.js"></script> <!-- parsing pauses here until big.js downloads AND runs -->

<p>...content after script (the user can't see this yet)...</p>

De esto se derivan dos consecuencias:

  • El script no puede ver los elementos del DOM que aparecen después de él, porque aún no han sido analizados.
  • El usuario observa una página construida parcialmente mientras se descarga el script. En redes lentas, este es el clásico problema de la "página en blanco".

La solución histórica era colocar los scripts al final del <body>. async y defer ofrecen una solución más limpia: mantén la etiqueta en <head> pero evita que bloquee.

Tanto async como defer solo afectan a los scripts externos: requieren el atributo src. Se ignoran en bloques <script> en línea.

Comprendiendo el atributo async

¿Qué es el atributo async?

Cuando añades el atributo async a una etiqueta <script>, le indicas al navegador que descargue el script en segundo plano sin bloquear el análisis del HTML. En cuanto finaliza la descarga, el navegador pausa el análisis, ejecuta el script y luego continúa. Dado que los tiempos de descarga varían, los scripts async se ejecutan en cuanto están listos — en un orden impredecible, posiblemente antes de que se haya analizado el resto del documento.

Esto hace que async sea ideal para scripts independientes que no dependen del DOM ni entre sí: analytics, publicidad y otros rastreadores de tipo "dispara y olvida".

Ejemplo de código: Uso de async

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Async Example</title>
</head>
<body>
    <h1>Testing Async</h1>
    <script async src="https://example.com/async-script.js"></script>
</body>
</html>

Ventajas e inconvenientes de async

  • No bloqueante: El análisis del HTML continúa mientras se descarga el script.
  • Se ejecuta cuanto antes: El script se ejecuta en el momento en que finaliza su descarga — ideal para scripts independientes.
  • Sin orden garantizado: Con varios scripts async, el que se descarga primero se ejecuta primero. Nunca uses async para scripts que dependan entre sí.
  • Puede ejecutarse antes de que el DOM esté listo: Puede ejecutarse antes de que termine el análisis, así que no asumas que existen elementos posteriores.

Aprovechando el atributo defer

¿Qué es el atributo defer?

El atributo defer también descarga el script en segundo plano sin bloquear el análisis. La diferencia está en cuándo se ejecuta: un script diferido se ejecuta solo después de que el documento HTML ha sido completamente analizado, y justo antes de que se dispare el evento DOMContentLoaded. Los scripts diferidos también mantienen su orden en el documento: la primera etiqueta defer siempre se ejecuta antes que la segunda, independientemente de cuál se descargue primero.

Esto hace que defer sea el valor predeterminado adecuado para el código de tu aplicación: se garantiza que todo el DOM existe y los scripts dependientes se mantienen en orden.

Ejemplo de código: Uso de defer

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Defer Example</title>
</head>
<body>
    <h1>Testing Defer</h1>
    <script defer src="https://example.com/defer-script.js"></script>
</body>
</html>

Ventajas del uso de defer

  • DOM listo: El documento HTML completo se analiza antes de que se ejecute el script.
  • Orden mantenido: Los scripts se ejecutan en el orden del documento, lo cual es esencial para scripts que dependen entre sí.

Los scripts de módulo se difieren por defecto

Un <script type="module"> se comporta como un script diferido automáticamente — no necesitas añadir defer. Se descarga sin bloquear el análisis y se ejecuta después de que el documento esté analizado, en orden. Para que un módulo se ejecute en cuanto esté listo (el comportamiento de async), añade async explícitamente:

<!-- Deferred automatically; runs after parsing, in order -->
<script type="module" src="app.js"></script>

<!-- Opt into async: runs as soon as it (and its imports) are ready -->
<script type="module" async src="tracker.js"></script>

Si eres nuevo en los módulos, consulta la Introducción a los módulos.

async vs defer de un vistazo

Comportamientoasyncdefer
¿Bloquea el análisis HTML?NoNo
¿Cuándo se ejecuta?En cuanto se descargaTras el análisis, antes de DOMContentLoaded
Orden de ejecuciónEl que se descarga primeroOrden del documento, garantizado
¿DOM completamente disponible?No garantizado
Ideal paraScripts independientes (analytics, publicidad)Código de la app, scripts dependientes

Una regla sencilla:

  • Usa async cuando el script sea independiente — no depende de otros scripts ni del DOM.
  • Usa defer cuando el script necesite todo el DOM, o cuando el orden de ejecución importe.

Ejemplo práctico: Decisiones de carga de scripts

Considera cargar una biblioteca de utilidades (como Lodash) más tu propio archivo que depende de ella. Dado que el orden importa aquí, defer es la elección correcta — ambos se descargan en segundo plano pero se ejecutan en secuencia después del análisis:

<script defer src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script defer src="script.js"></script>

Aquí se garantiza que lodash.min.js se ejecuta antes que script.js, y ambos esperan hasta que la página esté analizada. Cambiarlos a async arriesgaría que script.js se ejecute primero y falle porque Lodash aún no está cargado.

Para cargar recursos que no son scripts (imágenes, estilos) y reaccionar a su éxito o fallo, consulta Carga de recursos: onload y onerror.

Conclusión

Usar correctamente los atributos async y defer en las etiquetas de script es fundamental para el desarrollo web moderno. Al comprender y aplicar estos atributos correctamente, los desarrolladores pueden lograr cargas de página más rápidas y una mejor experiencia de usuario. La carga asíncrona de scripts tiene que ver con la optimización del rendimiento y la creación de aplicaciones web eficientes y centradas en el usuario.

Práctica

Práctica
¿Cuáles son los usos de los atributos 'async' y 'defer' en JavaScript?
¿Cuáles son los usos de los atributos 'async' y 'defer' en JavaScript?
Was this page helpful?