Dos tipos de JavaScript lento
No todo el JavaScript lento es igual. Hay una diferencia crucial entre:
- Script pesado: Mucho cálculo puro (loops, algoritmos, procesamiento de datos)
- Layout thrashing: Lee y escribe el DOM repetidamente, forzando recálculos de layout
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.