Todo lo que llamamos "lento" pasa por el mismo pasillo, y ese pasillo tiene una sola puerta. Entenderla es lo que convierte una queja en un diagnóstico.
Cuando abres una página, el navegador no guarda una fotografía: guarda una lista de piezas. Cada botón, cada texto, cada imagen es una pieza con su posición y su estilo. Esa lista se llama DOM, y es la única cosa que el navegador sabe dibujar.
Y aquí está el detalle que lo explica casi todo: el navegador trabaja con un solo par de manos. Colocar las piezas, pintarlas, ejecutar tu JavaScript y responder a tus clics pasan por el mismo sitio, que se llama hilo principal. No hay dos pasillos: hay uno.
La analogía útil es una cocina con un solo cocinero. Puede cortar, cocinar o atender al cliente, pero no las tres cosas a la vez. Si está cortando cebolla durante dos minutos, el cliente que levantó la mano espera dos minutos — aunque el plato esté casi listo.
Para convertir tu código en píxeles, el navegador hace siempre los mismos cinco pasos:
Los pasos 3, 4 y 5 se repiten cada vez que algo cambia. Y aquí aparece la primera regla incómoda: cambiar el tamaño o la posición de una pieza puede obligar a recalcular todas las demás. Por eso una lista de 5.000 filas no es "5.000 veces una fila": es un cálculo que las incluye a todas.
La segunda regla es el presupuesto de fotograma. Para que una animación se vea fluida, el navegador tiene unos 16,7 milisegundos por fotograma (60 por segundo). Todo lo que hagas —tu JavaScript, el layout, el paint— tiene que caber ahí. Si una sola tarea ocupa 120 ms, el navegador se salta siete fotogramas seguidos: eso es el tirón.
Con la cadena en la cabeza, solo existen cuatro formas de intervenir:
Quitar piezas de la mesa: no montar lo que no se ve, paginar, no renderizar datos que nadie mira.
Menos trabajo por fotograma: índices, cálculos fuera del render, debounce cuando de verdad aplica.
Sacar cómputo del hilo principal: un Web Worker. El pasillo queda libre; se paga en copiar datos.
Animar con transform y opacity evita recalcular posiciones; animar con top o width las recalcula todas.
Leer una medida del DOM y escribir un estilo, en bucle. Por ejemplo: leer
offsetHeight de cada fila y luego fijar su altura. Eso obliga al navegador a
recalcular el layout en cada vuelta del bucle. Es lo que se llama
layout thrashing, y convierte un bucle de 100 elementos en 100 recálculos
completos.
// MAL: alterna lectura y escritura → 100 recálculos de layout for (const fila of filas) { const alto = fila.offsetHeight; // leer fuerza layout fila.style.height = alto + 1 + 'px'; // escribir lo invalida } // BIEN: primero leo todo, después escribo todo → un solo recálculo const altos = filas.map((fila) => fila.offsetHeight); filas.forEach((fila, i) => { fila.style.height = altos[i] + 1 + 'px'; });
La regla de oro: no mires, graba. El panel de Performance graba lo que pasó y te deja ver el orden real de las cosas, cosa que la intuición siempre equivoca.
| Herramienta | Qué se mira | Cómo se ve el síntoma |
|---|---|---|
| Performance › grabar una interacción | Long Tasks | Barras rojas de más de 50 ms con un nombre de función dentro |
| Performance › Main | Quién ocupa el hilo | Un bloque amarillo enorme de JavaScript donde debía haber muchos pequeños |
| Performance › Rendering | Layout y paint repetidos | Barras moradas y verdes encadenadas; "Recalculate Style" muchas veces por segundo |
| Performance › CPU 4x slowdown | El mismo caso en una máquina lenta | Un tirón que en tu equipo no se ve aparece con claridad |
Tu laptop es más rápida que el teléfono de quien usa el producto. Si no reproduces el problema con la CPU frenada a propósito, no lo estás viendo: lo estás adivinando. Y en una entrevista eso se nota cuando te preguntan "¿y cómo confirmaste que era eso?".
“The browser has a single main thread, and layout, paint and my JavaScript all compete for it.”
“Anything above fifty milliseconds is a long task, and long tasks are what users feel as lag.”
“I'd record the interaction on a throttled CPU before touching the code.”
Comprueba que lo tienes
Cuatro preguntas. Al comprobar se marca la lección como completada.
¿Por qué un clic puede tardar en responder aunque la página "no esté haciendo nada"?
Por qué: todo pasa por un solo hilo. "No estar haciendo nada" visualmente no significa que el hilo esté libre: puede estar calculando o recalculando layout.
Quieres que una barra se deslice suavemente. ¿Cuál de las dos formas evita recalcular posiciones?
Por qué: transform y opacity no cambian la posición de nada más, así que el navegador puede componer sin recalcular el layout. left y width sí afectan al resto de las piezas.
Un bucle lee offsetHeight y luego escribe style.height, por cada fila. ¿Qué está pasando?
Por qué: leer una medida obliga al navegador a poner el layout al día. Si escribes justo después, lo invalidas. El bucle alterna las dos cosas y multiplica el costo por el número de elementos.
¿Cuál es el umbral que se usa para decir que una tarea es "larga"?
Por qué: 16,7 ms es el presupuesto para no perder fotogramas; 50 ms es el umbral práctico a partir del cual la interacción se percibe como lenta. Por eso las herramientas marcan en rojo lo que pasa de 50.