Depurando Race Conditions: Cuando DOMContentLoaded Falla
Desarrollo

Depurando Race Conditions: Cuando DOMContentLoaded Falla

26 Jan, 2026 • 4 min de lectura

A veces, las mejoras de rendimiento traen efectos secundarios inesperados. Recientemente, al migrar Becommerce.es a una infraestructura más rápida, una funcionalidad crítica dejó de funcionar: el buscador.

El síntoma era extraño: al hacer clic en la lupa, el modal se abría, pero el campo de texto para escribir no aparecía.

El Sospechoso: Race Condition

Una Race Condition (condición de carrera) ocurre cuando el comportamiento del software depende de la secuencia o el tiempo de eventos incontrolables. En este caso, la carga de la página vs. la ejecución del script.

El código original para iniciar el buscador (Pagefind) era este:

window.addEventListener('DOMContentLoaded', (event) => {
    new PagefindUI({ element: "#search" });
});

Este código le dice al navegador: “Espera a que el contenido esté listo (DOMContentLoaded), y entonces inicia el buscador”.

¿Por qué falló?

En el nuevo servidor, la página cargaba tan rápido que el evento DOMContentLoaded se disparaba antes de que el navegador llegara a leer y ejecutar nuestro bloque de script.

Cuando el script finalmente se ejecutaba y decía “avísame cuando cargues”, el navegador ya había terminado de cargar hacía milisegundos. El evento ya había pasado, y el aviso nunca llegaba. Resultado: el buscador nunca se iniciaba.

La Solución

La solución robusta es no asumir nada sobre el estado de la página. Debemos preguntar: “¿Ya estás lista? Si es así, ejecuta ahora. Si no, avísame cuando lo estés”.

Aquí está el código corregido que implementamos:

function initPagefind() {
    new PagefindUI({ element: "#search" });
}

// Comprobamos el estado actual antes de añadir el listener
if (document.readyState === 'loading') {
    // Aún cargando, esperamos al evento
    window.addEventListener('DOMContentLoaded', initPagefind);
} else {
    // Ya cargado (interactive o complete), ejecutamos inmediatamente
    initPagefind();
}

Al verificar document.readyState, cubrimos ambos escenarios: carga lenta (esperar evento) y carga rápida (ejecución inmediata), eliminando efectivamente la condición de carrera.

Actualización: Cuando Rocket Loader complica las cosas

Incluso con la solución anterior, en entornos que usan herramientas como Cloudflare Rocket Loader (que difiere la carga de scripts), es posible que la librería PagefindUI aún no esté definida cuando intentamos ejecutarla, independientemente del estado del DOM.

En estos casos, la solución definitiva es la perseverancia: un mecanismo de polling (reintento).

function initPagefind() {
    // Verificamos si la librería ya existe
    if (typeof PagefindUI !== "undefined") {
        new PagefindUI({ element: "#search" });
    } else {
        // Si no existe, esperamos 50ms y volvemos a intentarlo
        setTimeout(initPagefind, 50);
    }
}
initPagefind();

Este enfoque no confía en eventos ni estados del navegador, simplemente insiste cortésmente hasta que la herramienta necesaria está disponible. Esta técnica de “polling” ha demostrado ser la más efectiva contra los retrasos de carga introducidos por optimizaciones agresivas.