Cada vez que un navegador procesa una página web, realiza un trabajo intenso de parsing, descarga y ejecución de recursos. Aunque no podemos controlar cómo el navegador ejecuta internamente cada paso, sí podemos ayudarle a hacerlo de forma mucho más eficiente. La clave está en identificar y gestionar los recursos que lo bloquean, especialmente JavaScript y CSS.
¿Por qué JavaScript es un recurso bloqueante para el navegador?
Cuando el navegador encuentra una etiqueta <script> durante el HTML parsing, su comportamiento por defecto es detenerse por completo [01:00]. Esto significa que pausará la construcción del DOM para descargar el archivo JavaScript y ejecutarlo. Solo cuando esa ejecución termine, el navegador retomará el parsing del HTML.
Este comportamiento se conoce como recurso bloqueante: el navegador no puede avanzar hasta que el script se haya descargado y ejecutado. En un proyecto real, esto se traduce en tiempos de carga más largos y una experiencia degradada para el usuario.
¿Qué diferencia hay entre defer y async en la carga de scripts?
Existen dos atributos que modifican el comportamiento por defecto de la etiqueta <script> [01:42]:
- Defer (diferido): le indica al navegador que descargue el script en paralelo al parsing del HTML, pero que no lo ejecute hasta que el parsing haya finalizado por completo.
- Async (asíncrono): también descarga el script en paralelo, pero lo ejecuta inmediatamente al terminar la descarga, interrumpiendo el parsing del HTML en ese momento.
La diferencia fundamental es el momento de ejecución. Con defer, el HTML siempre se procesa primero. Con async, la ejecución puede ocurrir en cualquier punto, dependiendo de cuándo termine la descarga.
html
<!-- Comportamiento bloqueante por defecto -->
<script src="bundle.js"></script>
<!-- Descarga en paralelo, ejecuta al finalizar el parsing -->
<script src="bundle.js" defer></script>
<!-- Descarga en paralelo, ejecuta en cuanto se descargue -->
<script src="bundle.js" async></script>
¿Cómo verificar el bloqueo de scripts con Lighthouse y el profiler?
Para analizar el impacto real, se puede usar Lighthouse en Chrome Dev Tools [03:10]. Dentro de la pestaña Lighthouse, se genera un reporte seleccionando únicamente performance. Lo más relevante no es el puntaje numérico, sino el botón View Trace (ver el trazado), que muestra en detalle qué sucede en la línea de tiempo del navegador.
En el main thread del navegador se puede observar cómo, sin atributos en el script, el HTML parsing queda completamente detenido hasta que JavaScript termina su evaluación [04:28]. El hilo principal no libera el HTML hasta que el script se ha ejecutado por completo.
¿Qué sucede al agregar async a los scripts del proyecto?
Al cambiar las etiquetas <script> para incluir el atributo async, el resultado en el profiler es notablemente diferente [06:00]. El HTML parsing aparece concentrado a la izquierda de la línea de tiempo, y la evaluación de JavaScript ocurre después, hacia la derecha.
Esto significa que:
- El parsing del HTML ya no depende de JavaScript para finalizar.
- El navegador procesa primero el HTML completo.
- JavaScript se evalúa una vez que su descarga termina, sin haber bloqueado la construcción inicial del DOM.
El cambio en las métricas de Lighthouse también refleja esta mejora, con un puntaje de performance más alto [05:50].
¿Cómo aplicar este cambio en tu proyecto?
El ajuste es mínimo pero poderoso. En el archivo HTML del proyecto, basta con agregar async o defer a cada etiqueta <script> [05:15]:
html
<!-- Antes: bloqueante -->
<script src="app.js"></script>
<script src="vendor.js"></script>
<!-- Después: no bloqueante -->
<script src="app.js" async></script>
<script src="vendor.js" async></script>
La recomendación es experimentar con ambos atributos, generar reportes en Lighthouse y comparar los trazados del main thread para entender cuál se adapta mejor a cada caso. Con este ajuste tan simple, le quitamos al navegador un obstáculo importante y le permitimos construir el HTML de forma mucho más rápida y sin bloqueos.
¿Ya probaste cambiar entre async y defer en tu proyecto? Comparte en los comentarios qué diferencias encontraste en el profiler.