Ejemplo 10: Integración con DevTools

← Volver al índice

Debugging con DevTools

Long Animation Frames API funciona en conjunto con DevTools, no es un reemplazo. Esta demo muestra técnicas prácticas para usar LoAF mientras debuggeas en Chrome DevTools.

🚀 ¿Quieres usar estos helpers en cualquier página?

Hemos creado un WebPerf Snippet listo para copiar y pegar en DevTools. → Ver LoAF Helpers Snippet

💡
Tip clave:

Abre DevTools (F12) y ve a la pestaña Console mientras usas esta página. Los helpers están disponibles globalmente en window.loafHelpers.

Simular actividad

📊 Funciones disponibles en Console:
  • loafHelpers.summary() - Resumen de todos los frames
  • loafHelpers.topScripts(n) - Top N scripts más lentos
  • loafHelpers.exportCSV() - Descargar datos como CSV
  • loafHelpers.exportJSON() - Descargar datos como JSON
  • loafHelpers.clear() - Limpiar datos capturados

Helpers de debugging

Estos helpers están diseñados para usarse en la consola de DevTools durante el debugging. Se instalan automáticamente en window.loafHelpers.

1. Summary - Resumen rápido

Muestra un resumen de todos los frames capturados.

loafHelpers.summary()

Salida: Total frames, tiempo total, avg, max, distribución por severidad

2. Top Scripts - Scripts más problemáticos

Lista los N scripts con mayor impacto.

loafHelpers.topScripts(5) // Top 5 scripts

Salida: Tabla con sourceURL, función, duración, forzado layout

3. Filter by Duration - Filtrar por duración

Mostrar solo frames que superen cierto umbral.

loafHelpers.filter({ minDuration: 200 })

4. Find by URL - Buscar por script

Filtrar frames que incluyan un script específico.

loafHelpers.findByURL('analytics')

5. Export Data - Exportar datos

Descargar todos los datos capturados para análisis externo.

loafHelpers.exportJSON() // Descarga JSON loafHelpers.exportCSV() // Descarga CSV

Workflow recomendado

1. Durante desarrollo

// En Console de DevTools:
// 1. Usar la página normalmente
// 2. Ver resumen
loafHelpers.summary()

// 3. Identificar scripts problemáticos
loafHelpers.topScripts(10)

// 4. Filtrar frames críticos
loafHelpers.filter({ minDuration: 200 })

// 5. Buscar un script específico
loafHelpers.findByURL('my-component')

2. Para análisis profundo

// 1. Exportar datos
loafHelpers.exportJSON()

// 2. Analizar en herramienta externa
// - Excel/Google Sheets
// - Script de Python/Node.js
// - BI tools (Tableau, Metabase, etc.)

// 3. O acceder a datos raw
const data = loafHelpers.getRawData()
console.table(data)

3. Performance recording

🎥
Combinar con Performance panel:
  1. Abre DevTools → Performance
  2. Click "Record" 🔴
  3. Reproduce el problema
  4. Stop recording
  5. En Console: loafHelpers.summary() para correlacionar

Los timestamps de LoAF coinciden con el timeline de Performance, puedes correlacionar frames lentos con eventos específicos.

Console API útiles

console.table() para LoAF

// Mostrar scripts en tabla ordenada
const frames = performance.getEntriesByType('long-animation-frame');
const scripts = frames.flatMap(f => f.scripts).map(s => ({
  url: new URL(s.sourceURL || location.href).pathname,
  function: s.sourceFunctionName || '(anónima)',
  duration: s.duration.toFixed(2) + 'ms',
  forced: s.forcedStyleAndLayoutDuration.toFixed(2) + 'ms'
}));

console.table(scripts);

console.group() para organización

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.group(`Frame lento: ${entry.duration.toFixed(2)}ms`);

    console.log('Duración total:', entry.duration);
    console.log('Render start:', entry.renderStart);
    console.log('Scripts:', entry.scripts.length);

    console.groupCollapsed('Detalle de scripts');
    entry.scripts.forEach(s => {
      console.log(s.sourceURL, s.duration);
    });
    console.groupEnd();

    console.groupEnd();
  }
});

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

console.time() para mediciones

// Medir cuánto tarda en detectarse un frame lento
button.addEventListener('click', () => {
  console.time('hasta-loaf');

  // Operación pesada
  heavyWork();
});

const observer = new PerformanceObserver((list) => {
  console.timeEnd('hasta-loaf');
});

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

DevTools Performance panel

⚠️ Importante:

LoAF API captura información que complementa el Performance panel, no lo reemplaza. Usa ambos en conjunto:

  • Performance panel: Flamegraph detallado, waterfall, screenshots
  • LoAF API: Attribution automática, análisis en producción, métricas agregadas

Correlacionar LoAF con timeline

// Capturar timestamp de frames lentos
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(
      `Frame lento en ${entry.startTime.toFixed(2)}ms` +
      ` (duración: ${entry.duration.toFixed(2)}ms)`
    );

    // Buscar en timeline de Performance panel alrededor de startTime
    // para ver el flamegraph detallado
  }
});

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

Performance marks

// Marcar eventos específicos para correlacionar
function heavyOperation() {
  performance.mark('heavy-operation-start');

  // ... trabajo pesado

  performance.mark('heavy-operation-end');
  performance.measure(
    'heavy-operation',
    'heavy-operation-start',
    'heavy-operation-end'
  );
}

// En DevTools Performance, verás las marks en el timeline
// Y en LoAF verás si causaron frames lentos

Snippets útiles

Snippet: Auto-log de frames críticos

// Guardar como Snippet en DevTools → Sources → Snippets
(function() {
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (entry.duration > 200) {
        console.group(`🚨 Frame crítico: ${entry.duration.toFixed(2)}ms`);
        console.log('Timestamp:', entry.startTime);
        console.log('Scripts involucrados:', entry.scripts.length);

        const topScript = entry.scripts.reduce((max, s) =>
          s.duration > max.duration ? s : max
        );

        console.warn('Script más lento:', {
          url: topScript.sourceURL,
          function: topScript.sourceFunctionName,
          duration: topScript.duration
        });

        console.groupEnd();
      }
    }
  });

  observer.observe({ type: 'long-animation-frame', buffered: true });
  console.log('✅ Monitoring de frames críticos activado');
})();

Snippet: Comparador de sesiones

// Capturar baseline y comparar después
window.loafBaseline = {
  capture() {
    const frames = performance.getEntriesByType('long-animation-frame');
    this.data = {
      count: frames.length,
      totalTime: frames.reduce((sum, f) => sum + f.duration, 0),
      avgDuration: frames.reduce((sum, f) => sum + f.duration, 0) / frames.length,
      timestamp: Date.now()
    };
    console.log('📊 Baseline capturado:', this.data);
  },

  compare() {
    const frames = performance.getEntriesByType('long-animation-frame');
    const current = {
      count: frames.length,
      totalTime: frames.reduce((sum, f) => sum + f.duration, 0),
      avgDuration: frames.reduce((sum, f) => sum + f.duration, 0) / frames.length
    };

    console.group('📈 Comparación vs Baseline');
    console.log('Frames:', current.count, 'vs', this.data.count,
      `(${((current.count / this.data.count - 1) * 100).toFixed(1)}%)`);
    console.log('Avg duration:', current.avgDuration.toFixed(2) + 'ms', 'vs',
      this.data.avgDuration.toFixed(2) + 'ms',
      `(${((current.avgDuration / this.data.avgDuration - 1) * 100).toFixed(1)}%)`);
    console.groupEnd();
  }
};

// Uso:
// loafBaseline.capture()  // Antes de cambio
// ... hacer cambios ...
// loafBaseline.compare()  // Después de cambio

💾 Exportar datos de esta sesión

Descarga los datos capturados para análisis offline: