Ejemplo 08: Long Tasks vs LoAF

← Volver al índice

Dos APIs para detectar JavaScript lento

Antes de LoAF, existía Long Tasks API (disponible desde Chrome 58, 2017). Ambas detectan JavaScript que bloquea el main thread, pero con diferentes niveles de detalle.

🕐 Long Tasks API (2017)

Detecta tareas que tardan más de 50ms, pero con información limitada

🚀 Long Animation Frames API (2023)

Detecta frames lentos con contexto completo: qué scripts, qué funciones, cuánto layout thrashing

Comparación lado a lado

Long Tasks API

Long Animation Frames API

📊 Comparación:
Haz clic en el botón para comparar ambas APIs

Long Tasks API

Configuración básica

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('Long task detected:');
    console.log('  Duration:', entry.duration);
    console.log('  Start time:', entry.startTime);
    console.log('  Name:', entry.name);
    console.log('  Attribution:', entry.attribution);
  }
});

observer.observe({ type: 'longtask', buffered: true });

Información disponible

{
  name: "self",
  entryType: "longtask",
  startTime: 1234.5,
  duration: 234.2,
  attribution: [{
    name: "unknown",
    entryType: "taskattribution",
    containerType: "window",
    containerName: "",
    containerId: ""
  }]
}
⚠️ Limitaciones de Long Tasks API:
  • ❌ No muestra qué script causó la tarea
  • ❌ No muestra qué función se ejecutó
  • ❌ No distingue entre cálculo y layout thrashing
  • ❌ Solo attribution genérica (iframe, window)
  • ✅ Solo útil para saber "algo fue lento"

Long Animation Frames API

Configuración básica

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('Long frame detected:');
    console.log('  Duration:', entry.duration);
    console.log('  Blocking duration:', entry.blockingDuration);
    console.log('  Scripts:', entry.scripts.length);

    entry.scripts.forEach(script => {
      console.log('    Function:', script.sourceFunctionName);
      console.log('    File:', script.sourceURL);
      console.log('    Duration:', script.duration);
      console.log('    Forced layout:', script.forcedStyleAndLayoutDuration);
    });
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });

Información disponible

{
  name: "long-animation-frame",
  entryType: "long-animation-frame",
  startTime: 1234.5,
  duration: 234.2,
  renderStart: 1234.8,
  styleAndLayoutStart: 1235.0,
  blockingDuration: 184.2,
  scripts: [{
    invoker: "BUTTON.onclick",
    sourceFunctionName: "handleClick",
    sourceURL: "http://example.com/app.js",
    sourceCharPosition: 1234,
    duration: 200.5,
    executionStart: 1234.6,
    forcedStyleAndLayoutDuration: 120.3,
    pauseDuration: 0
  }]
}
✅ Ventajas de Long Animation Frames API:
  • ✅ Muestra exactamente qué script y función
  • ✅ Incluye URL y posición en el archivo
  • ✅ Distingue cálculo vs layout thrashing
  • ✅ Muestra el "invoker" (qué disparó el script)
  • ✅ Información completa para debugging

Comparación directa

Característica Long Tasks Long Animation Frames
Disponibilidad Chrome 58+ (2017) Chrome 116+ (2023)
Umbral > 50ms > 50ms
Script attribution ❌ No ✅ Sí (función, URL)
Forced layout ❌ No ✅ Sí
Render timing ❌ No ✅ Sí (renderStart)
Útil para debugging 🟡 Limitado ✅ Excelente
Uso recomendado Detección básica Debugging y optimización

¿Cuándo usar cada API?

Usa Long Tasks API cuando:

Usa Long Animation Frames API cuando:

💡 Estrategia híbrida:

Usa Long Tasks como fallback para navegadores antiguos, y Long Animation Frames cuando esté disponible para obtener información detallada.

Migración de Long Tasks a LoAF

Código compatible con ambas APIs

// Feature detection
const supportsLoaf = PerformanceObserver.supportedEntryTypes.includes(
  'long-animation-frame'
);

if (supportsLoaf) {
  // Usar LoAF (preferido)
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.log('Frame lento:', entry.duration);
      entry.scripts.forEach(script => {
        console.log('  Función:', script.sourceFunctionName);
      });
    }
  });

  observer.observe({ type: 'long-animation-frame', buffered: true });
} else {
  // Fallback a Long Tasks
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.log('Tarea lenta:', entry.duration);
      // Información limitada disponible
    }
  });

  observer.observe({ type: 'longtask', buffered: true });
}