Ejemplo 07: Script pesado vs Layout Thrashing

← Volver al índice

Dos tipos de JavaScript lento

No todo el JavaScript lento es igual. Hay una diferencia crucial entre:

LoAF API nos permite distinguir entre ambos usando forcedStyleAndLayoutDuration.

Comparación

📊 Último frame detectado:
Haz clic en uno de los botones...

Comparación de métricas:

Análisis detallado:

¿Qué es forcedStyleAndLayoutDuration?

Es el tiempo que el navegador pasó recalculando estilos y layout de forma forzada durante la ejecución de un script.

Script pesado (sin layout thrashing)

function heavyComputation() {
  let result = 0;

  // Cálculo puro (no toca el DOM)
  for (let i = 0; i < 10000000; i++) {
    result += Math.sqrt(i) * Math.random();
  }

  return result;
}

// LoAF muestra:
// duration: 200ms
// forcedStyleAndLayoutDuration: 0ms ← ¡Sin recálculos!

Layout thrashing (fuerza recálculos)

function layoutThrashing() {
  const elements = document.querySelectorAll('.item');

  elements.forEach(el => {
    // 1. LEER (fuerza layout)
    const height = el.offsetHeight;

    // 2. ESCRIBIR (invalida layout)
    el.style.width = (height + 10) + 'px';

    // → Navegador debe recalcular TODO antes de la siguiente lectura
  });
}

// LoAF muestra:
// duration: 200ms
// forcedStyleAndLayoutDuration: 180ms ← ¡90% fue recálculos!

Interpretando los resultados

Ratio de layout thrashing

const ratio = (forcedStyleAndLayoutDuration / duration) * 100;

if (ratio > 50) {
  console.log('🔴 Problema: Layout thrashing severo');
  console.log('Solución: Batch reads y writes del DOM');
}

if (ratio < 10 && duration > 200) {
  console.log('🟡 Problema: Cálculo pesado');
  console.log('Solución: Web Workers o dividir en chunks');
}

Diferentes soluciones según el problema

Problema Identificación Solución
Layout thrashing forcedStyleAndLayoutDuration > 50% de duration Batch reads/writes, usar requestAnimationFrame
Cálculo pesado duration alto, forcedStyleAndLayoutDuration bajo Web Workers, dividir en chunks, algoritmos más eficientes
Mixto Ambos valores altos Combinar soluciones

Cómo arreglar layout thrashing

❌ Mal: Leer y escribir alternado

elements.forEach(el => {
  const height = el.offsetHeight;  // LEER (fuerza layout)
  el.style.width = height + 'px';  // ESCRIBIR (invalida)
  // → Próxima iteración fuerza recálculo completo
});

✅ Bien: Primero leer todo, luego escribir todo

// Fase 1: Solo LEER (un único layout)
const heights = Array.from(elements).map(el => el.offsetHeight);

// Fase 2: Solo ESCRIBIR (sin forzar recálculos)
elements.forEach((el, i) => {
  el.style.width = heights[i] + 'px';
});
✅ Resultado:
  • Antes: 200ms (180ms de forced layout)
  • Después: 20ms (0ms de forced layout)
  • 10x más rápido

Propiedades que fuerzan layout

Estas propiedades obligan al navegador a calcular el layout inmediatamente:

Dimensiones

element.offsetWidth
element.offsetHeight
element.clientWidth
element.clientHeight
element.scrollWidth
element.scrollHeight

Posición

element.offsetTop
element.offsetLeft
element.clientTop
element.clientLeft
element.scrollTop
element.scrollLeft

Métodos

element.getBoundingClientRect()
element.getClientRects()
window.getComputedStyle(element)
⚠️ Importante:

No todas las lecturas del DOM fuerzan layout. Por ejemplo, element.classList o element.textContent no lo hacen. Solo las propiedades que requieren cálculos geométricos.