
> Referencia rápida de términos, acrónimos y conceptos relacionados con LoAF y web performance.

<details>
<summary>📋 <strong>Índice</strong> <em>(click para expandir)</em></summary>

- [APIs y Métricas](#apis-y-métricas)
  - [LoAF (Long Animation Frames API)](#loaf-long-animation-frames-api)
  - [INP (Interaction to Next Paint)](#inp-interaction-to-next-paint)
  - [LCP (Largest Contentful Paint)](#lcp-largest-contentful-paint)
  - [CLS (Cumulative Layout Shift)](#cls-cumulative-layout-shift)
  - [FID (First Input Delay) [Deprecado]](#fid-first-input-delay-deprecado)
  - [TBT (Total Blocking Time)](#tbt-total-blocking-time)
  - [Event Timing API](#event-timing-api)
  - [Long Tasks API](#long-tasks-api)

- [Conceptos de Performance](#conceptos-de-performance)
  - [Frame](#frame)
  - [Long Animation Frame](#long-animation-frame)
  - [Long Task](#long-task)
  - [Blocking Duration](#blocking-duration)
  - [Attribution](#attribution)
  - [Layout Thrashing / Forced Synchronous Layout](#layout-thrashing--forced-synchronous-layout)
  - [Forced Style and Layout Duration](#forced-style-and-layout-duration)

- [Técnicas de Medición](#técnicas-de-medición)
  - [RUM (Real User Monitoring)](#rum-real-user-monitoring)
  - [Synthetic Monitoring](#synthetic-monitoring)
  - [Sampling](#sampling)
  - [Percentiles (P50, P75, P95, P99)](#percentiles-p50-p75-p95-p99)
  - [Buffered Observations](#buffered-observations)
  - [Beacon](#beacon)

- [Propiedades de LoAF](#propiedades-de-loaf)
  - [entry.duration](#entryduration)
  - [entry.blockingDuration](#entryblockingduration)
  - [entry.renderStart](#entryrenderstart)
  - [entry.styleAndLayoutStart](#entrystyleandlayoutstart)
  - [entry.scripts](#entryscripts)
  - [script.sourceURL](#scriptsourceurl)
  - [script.sourceFunctionName](#scriptsourcefunctionname)
  - [script.duration](#scriptduration)
  - [script.forcedStyleAndLayoutDuration](#scriptforcedstyleandlayoutduration)
  - [script.invoker](#scriptinvoker)

- [Términos de Optimización](#términos-de-optimización)
  - [Code Splitting](#code-splitting)
  - [Lazy Loading](#lazy-loading)
  - [Debouncing](#debouncing)
  - [Throttling](#throttling)
  - [Memoization](#memoization)
  - [FastDOM](#fastdom)
  - [requestIdleCallback](#requestidlecallback)
  - [requestAnimationFrame](#requestanimationframe)

- [Scripts y Orígenes](#scripts-y-orígenes)
  - [First-party Script](#first-party-script)
  - [Third-party Script](#third-party-script)
  - [Inline Script](#inline-script)
  - [External Script](#external-script)
  - [Minified Code](#minified-code)
  - [Source Maps](#source-maps)

- [Herramientas](#herramientas)
  - [DevTools Performance Panel](#devtools-performance-panel)
  - [Lighthouse](#lighthouse)
  - [WebPageTest](#webpagetest)
  - [Chrome User Experience Report (CrUX)](#chrome-user-experience-report-crux)
  - [Web Vitals Extension](#web-vitals-extension)

- [Referencias Rápidas](#referencias-rápidas)
  - [Umbrales Críticos](#umbrales-críticos)
  - [Compatibilidad](#compatibilidad)
  - [APIs Relacionadas (Cronología)](#apis-relacionadas-cronología)

- [Recursos de Aprendizaje](#recursos-de-aprendizaje)
  - [Documentación Oficial](#documentación-oficial)
  - [Artículos y Guías](#artículos-y-guías)
  - [Herramientas y Recursos](#herramientas-y-recursos)
  - [Casos de Éxito](#casos-de-éxito)

</details>

---

## APIs y Métricas

### LoAF (Long Animation Frames API)

API de Chrome 116+ que captura frames de animación lentos (>50ms) con attribution detallada de scripts y funciones responsables. A diferencia de Long Tasks API, LoAF proporciona información específica sobre qué función en qué archivo causó el problema.

**Ejemplo:**

```javascript
{
  duration: 264,
  scripts: [{
    sourceURL: "checkout.js",
    sourceFunctionName: "validateCoupon",
    duration: 218
  }]
}
```

---

### INP (Interaction to Next Paint)

Core Web Vital que mide la **latencia de interacciones** del usuario durante toda la vida de la página. Captura la peor interacción (P98) entre click, tap, y keyboard input.

**Umbrales:**

- 🟢 **Good:** ≤200ms
- 🟡 **Needs Improvement:** 200-500ms
- 🔴 **Poor:** >500ms

**Por qué importa:** Desde marzo 2024, INP es Core Web Vital oficial y puede afectar el ranking de búsqueda.

**Referencias:**

- <a href="https://web.dev/inp/" target="_blank" rel="noopener">Web.dev: INP</a>
- <a href="https://web.dev/optimize-inp/" target="_blank" rel="noopener">Chrome Docs: Optimize INP</a>

---

### LCP (Largest Contentful Paint)

Core Web Vital que mide **cuándo el contenido más grande** se renderiza en el viewport. Típicamente es una imagen hero, video, o bloque de texto grande.

**Umbrales:**

- 🟢 **Good:** <2.5s
- 🟡 **Needs Improvement:** 2.5-4s
- 🔴 **Poor:** >4s

**Relación con LoAF:** Scripts que se ejecutan durante carga inicial pueden bloquear o retrasar LCP.

---

### CLS (Cumulative Layout Shift)

Core Web Vital que mide **estabilidad visual**. Suma todos los layout shifts inesperados durante la vida de la página.

**Umbrales:**

- 🟢 **Good:** <0.1
- 🟡 **Needs Improvement:** 0.1-0.25
- 🔴 **Poor:** >0.25

---

### FID (First Input Delay) [Deprecado]

Métrica anterior a INP que medía la latencia de la **primera interacción** solamente. Reemplazado por INP en marzo 2024.

**Por qué se reemplazó:** FID solo medía input delay de la primera interacción, ignorando el processing time y todas las interacciones subsecuentes.

---

### TBT (Total Blocking Time)

Métrica de Lighthouse que suma el tiempo bloqueante de todas las Long Tasks entre FCP (First Contentful Paint) y TTI (Time to Interactive).

**Relación con LoAF:** TBT se calcula a partir de Long Tasks, mientras que LoAF proporciona más detalle (attribution).

**Umbral:** <200ms es considerado bueno en Lighthouse.

---

### Event Timing API

API que captura métricas de latencia de eventos de usuario (click, keydown, etc.).

**Qué proporciona:**

- ✅ Tipo de evento (click, input, keypress)
- ✅ Duración total (input delay + processing + presentation)
- ✅ Target element
- ❌ **No proporciona:** Qué función/script causó la latencia

**Uso típico:** Calcular INP en producción.

```javascript
new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.duration > 200) {
      console.log("Slow interaction:", entry.name, entry.duration);
    }
  }
}).observe({ type: "event", buffered: true });
```

---

### Long Tasks API

API (2017) que captura tareas que exceden 50ms en el main thread.

**Qué proporciona:**

- ✅ Duración de la tarea
- ✅ Timestamp de inicio
- ⚠️ Attribution limitada (solo container)
- ❌ **No proporciona:** Qué función específica, forzado de layout

**Relación con LoAF:** LoAF es la evolución de Long Tasks con attribution detallada.

**Cuándo usar:** Fallback para navegadores sin soporte de LoAF (Firefox, Safari).

---

## Conceptos de Performance

### Frame

Un **ciclo completo de renderizado** en el navegador:

1. JavaScript execution
2. Style calculation
3. Layout calculation
4. Paint
5. Composite

**Objetivo:** 60fps = 16.67ms por frame (para animaciones suaves)

---

### Long Animation Frame

Frame que **excede 50ms** de duración, capturado por LoAF API. El umbral de 50ms se eligió porque representa aproximadamente 3 frames a 60fps.

**Por qué 50ms:** Es el umbral donde los usuarios comienzan a percibir lag en interacciones.

---

### Long Task

Tarea que **excede 50ms** en el main thread, capturada por Long Tasks API. Similar a Long Animation Frame pero sin attribution detallada.

---

### Blocking Duration

Parte del frame que **excede 50ms** y bloquea interacciones del usuario. Es diferente de la duración total del frame.

**Fórmula:**

```javascript
blockingDuration = Math.max(0, duration - 50);
```

**Ejemplo:**

- Frame duration: 150ms → Blocking duration: 100ms
- Frame duration: 40ms → Blocking duration: 0ms

---

### Attribution

Información detallada sobre **QUÉ código** causó un problema de performance. Incluye:

- Nombre de función (`sourceFunctionName`)
- URL del archivo (`sourceURL`)
- Duración específica
- Forced layout duration

**Antes de LoAF:** Attribution manual en DevTools
**Con LoAF:** Attribution automática en producción

---

### Layout Thrashing / Forced Synchronous Layout

Anti-patrón donde alternas **lecturas y escrituras del DOM** en un bucle, forzando recálculos de layout costosos.

**Ejemplo problemático:**

```javascript
for (let i = 0; i < 100; i++) {
  const height = element.offsetHeight; // READ → fuerza layout
  element.style.width = height + "px"; // WRITE → invalida layout
  // Next iteration: layout recalculation needed again
}
// 100 iteraciones = 100 recálculos de layout
```

**Solución:**

```javascript
// Batch reads
const measurements = elements.map(el => el.offsetHeight);

// Batch writes
elements.forEach((el, i) => (el.style.width = measurements[i] + "px"));
```

**Referencias:**

- <a href="https://web.dev/articles/avoid-large-complex-layouts-and-layout-thrashing#avoid_layout_thrashing" target="_blank" rel="noopener">Avoid layout thrashing</a>
- <a href="https://gist.github.com/paulirish/5d52fb081b3570c81e3a" target="_blank" rel="noopener">Paul Irish: What forces layout/reflow</a>

---

### Forced Style and Layout Duration

Tiempo que un script gasta en **recálculos forzados** de style y layout. Expuesto por LoAF como `forcedStyleAndLayoutDuration`.

**Causas comunes:**

- Leer propiedades geométricas (`offsetHeight`, `clientWidth`, `getBoundingClientRect()`)
- Después de modificar el DOM
- Dentro de loops

**Interpretación:**

- 0ms → No hay forced layout (normal)
- > 50ms → Posible layout thrashing
- > 30% del script duration → Problema serio

---

## Técnicas de Medición

### RUM (Real User Monitoring)

Monitoreo de performance con **datos de usuarios reales** en producción, en contraste con testing sintético en ambiente controlado.

**Ventajas:**

- ✅ Refleja experiencia real
- ✅ Captura variedad de dispositivos/redes
- ✅ Detecta problemas que no aparecen en lab

**Desventajas:**

- ❌ Overhead en producción (mitigable con sampling)
- ❌ Privacy considerations
- ❌ Requiere infraestructura de backend

---

### Synthetic Monitoring

Monitoreo con herramientas automatizadas (Lighthouse, WebPageTest) en **ambiente controlado**.

**Ventajas:**

- ✅ Reproducible
- ✅ Sin overhead en producción
- ✅ Fácil de configurar en CI/CD

**Desventajas:**

- ❌ No refleja usuarios reales
- ❌ Variabilidad entre runs
- ❌ Puede perder problemas específicos de producción

---

### Sampling

Capturar solo un **porcentaje de eventos** para reducir overhead. Crítico para RUM en producción.

**Ejemplo:**

```javascript
if (Math.random() < 0.1) {
  // 10% sampling
  captureLoafData(entry);
}
```

**Reglas de oro:**

- **Alto tráfico (>1M visitas/mes):** 1-5% sampling
- **Tráfico medio (100K-1M):** 5-10% sampling
- **Bajo tráfico (<100K):** 10-25% sampling

**Por qué funciona:** Con suficiente volumen, 10% de muestras es estadísticamente significativo.

---

### Percentiles (P50, P75, P95, P99)

Estadísticas que muestran **distribución de valores**, más útiles que promedios para performance.

**Definiciones:**

- **P50 (mediana):** 50% de valores están por debajo
- **P75:** 75% de valores están por debajo (recomendado por Google para Core Web Vitals)
- **P95:** 95% de valores están por debajo (captura outliers sin incluir anomalías extremas)
- **P99:** 99% de valores están por debajo (usuarios más afectados)

**Por qué no usar promedio:**

```javascript
// 90 frames de 75ms, 8 frames de 125ms, 2 frames de 800ms
avg = 91.5ms   // ❌ Esconde los 2 frames problemáticos
P50 = 75ms     // Experiencia típica
P75 = 75ms     // Experiencia de mayoría
P95 = 800ms    // ✅ Revela los outliers
```

**Referencias:**

- <a href="https://web.dev/user-centric-performance-metrics/" target="_blank" rel="noopener">Google: User-centric performance metrics</a>

---

### Buffered Observations

Capturar entries que ocurrieron **ANTES** de que el observer se registrara. Crítico para capturar eventos durante page load.

```javascript
observer.observe({
  type: "long-animation-frame",
  buffered: true, // ← Incluye entries anteriores
});
```

**Sin `buffered: true`:** Pierdes todos los frames que ocurrieron antes del observer.

---

### Beacon

Envío de datos a servidor de forma **no bloqueante** usando `navigator.sendBeacon()`.

**Ventajas:**

- ✅ No bloquea el main thread
- ✅ Garantiza envío incluso si usuario cierra la página
- ✅ No requiere esperar respuesta

**Limitaciones:**

- ❌ Payload máximo ~64KB
- ❌ Solo POST requests
- ❌ No puedes leer la respuesta

```javascript
const data = JSON.stringify({ metrics: {...} });
const blob = new Blob([data], { type: 'application/json' });
navigator.sendBeacon('/api/analytics', blob);
```

---

## Propiedades de LoAF

### entry.duration

Duración **total del frame** (JavaScript + Rendering + overhead). Incluye todos los scripts y el rendering subsecuente.

```javascript
const entry = performance.getEntriesByType("long-animation-frame")[0];
console.log(entry.duration); // ej: 264ms
```

---

### entry.blockingDuration

Tiempo del frame que **excede 50ms** y bloquea interacciones del usuario.

```javascript
blockingDuration = Math.max(0, duration - 50);
```

---

### entry.renderStart

Timestamp cuando comienza el **rendering** (después de que JavaScript terminó).

**Uso:** Calcular cuánto tiempo se empleó en JavaScript vs rendering.

```javascript
const jsTime = entry.renderStart - entry.startTime;
const renderTime = entry.duration - jsTime;
```

---

### entry.styleAndLayoutStart

Timestamp cuando comienza el cálculo de **style y layout**.

---

### entry.scripts

Array de **scripts** que ejecutaron durante el frame. Cada script tiene su propia attribution.

```javascript
entry.scripts.forEach(script => {
  console.log(script.sourceURL); // Archivo
  console.log(script.sourceFunctionName); // Función
  console.log(script.duration); // Tiempo
});
```

---

### script.sourceURL

URL del **archivo** que contiene el script.

**Casos comunes:**

- `"https://example.com/app.js"` → Script externo normal
- `"https://cdn.jsdelivr.net/npm/library@1.0.0/dist/bundle.js"` → Script desde CDN
- `"/static/js/main.123.js"` → Script local con hash

**Casos especiales:**

- `""` (vacío) → Script inline sin sourceURL
- `"unknown"` → Script generado con eval() o new Function()
- `"chrome-extension://..."` → Script de extensión de navegador

---

### script.sourceFunctionName

Nombre de la **función** que se invocó.

**Limitaciones:**

- `""` (vacío) → Función anónima o código global
- `"a"`, `"b"`, `"Hc"` → Código minificado (nombres obfuscados)
- Solo útil con código no minificado o con source maps

**Implicación para producción:** En scripts third-party minificados, este campo es casi inútil. Identifica por `sourceURL` (dominio) en su lugar.

---

### script.duration

Tiempo que **ese script específico** consumió ejecutando JavaScript. No incluye rendering.

**Diferencia con frame duration:**

```javascript
Frame duration: 200ms      // Frame completo
Script duration: 120ms     // Solo JavaScript de ese script
Difference: 80ms           // Rendering + otros scripts + overhead
```

---

### script.forcedStyleAndLayoutDuration

Tiempo que ese script gastó en **recálculos forzados** de style y layout (layout thrashing).

**Interpretación:**

- `0ms` → No hay forced layout (código limpio)
- `>0ms pero <20% del script.duration` → Aceptable
- `>30% del script.duration` → Layout thrashing severo

```javascript
if (script.forcedStyleAndLayoutDuration > script.duration * 0.3) {
  console.warn("Layout thrashing detected!");
}
```

---

### script.invoker

Qué **invocó** el script. Puede ser un event handler, un timer, etc.

**Ejemplos:**

- `"IMG#hero.onload"` → Image load event
- `"BUTTON#submit.onclick"` → Click event
- `"Window.setTimeout"` → setTimeout callback
- `"Window.requestAnimationFrame"` → rAF callback

**Uso:** Correlacionar script con interacción o evento específico.

---

## Términos de Optimización

### Code Splitting

Dividir código en **chunks más pequeños** que cargan on-demand, reduciendo el bundle inicial.

**Ejemplo (Webpack):**

```javascript
import(/* webpackChunkName: "heavy" */ "./heavy-module.js").then(module =>
  module.doSomething()
);
```

**Ejemplo (Vite):**

```javascript
// Vite soporta dynamic imports nativamente
import("./heavy-module.js").then(module => module.doSomething());

// Con React + Vite
const HeavyComponent = lazy(() => import("./HeavyComponent"));

// Con Vue + Vite
const HeavyComponent = defineAsyncComponent(
  () => import("./HeavyComponent.vue")
);
```

---

### Lazy Loading

Cargar recursos solo **cuando se necesitan**, no durante la carga inicial.

**Ejemplo (third-party script):**

```javascript
// ❌ Carga inmediata
<script src="analytics.js"></script>;

// ✅ Lazy load después de interacción
button.addEventListener(
  "click",
  () => {
    import("./analytics.js").then(module => module.track(event));
  },
  { once: true }
);
```

---

### Debouncing

Retrasar ejecución de función hasta que pasen **X milisegundos sin nuevos eventos**.

**Uso típico:** Input field que dispara búsqueda.

```javascript
const debounce = (fn, delay) => {
  let timeout;
  return (...args) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => fn(...args), delay);
  };
};

input.addEventListener("input", debounce(search, 300));
```

---

### Throttling

Limitar **frecuencia de ejecución** de función (máximo 1 vez cada X ms).

**Uso típico:** Scroll handler.

```javascript
const throttle = (fn, limit) => {
  let inThrottle;
  return (...args) => {
    if (!inThrottle) {
      fn(...args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
};

window.addEventListener("scroll", throttle(onScroll, 100));
```

---

### Memoization

Cachear **resultados de funciones costosas** para evitar recalcular.

```javascript
const memoize = fn => {
  const cache = new Map();
  return (...args) => {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
};

const expensiveCalc = memoize(n => {
  // Cálculo costoso
  return result;
});
```

---

### FastDOM

Librería que **batches lecturas y escrituras** del DOM para evitar layout thrashing.

```javascript
import fastdom from "fastdom";

// Batch reads
fastdom.measure(() => {
  const height = element.offsetHeight;

  // Batch writes
  fastdom.mutate(() => {
    element.style.width = height + "px";
  });
});
```

**Referencias:**

- <a href="https://github.com/wilsonpage/fastdom" target="_blank" rel="noopener">FastDOM GitHub</a>

---

### requestIdleCallback

API para ejecutar código durante **periodos idle** del navegador, sin afectar performance.

```javascript
requestIdleCallback(deadline => {
  while (deadline.timeRemaining() > 0 && tasks.length > 0) {
    const task = tasks.pop();
    task();
  }
});
```

**Cuidado:** No soportado en Safari (usar polyfill).

---

### requestAnimationFrame

API para sincronizar código con **refresh rate del display** (típicamente 60fps = ~16.67ms).

**Uso típico:** Animaciones suaves.

```javascript
function animate() {
  // Update animation
  element.style.transform = `translateX(${x}px)`;

  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
```

---

## Scripts y Orígenes

### First-party Script

Script del **mismo dominio** que la página.

**Ejemplo:**

- Página: `https://example.com/page`
- Script: `https://example.com/app.js` ✅ First-party

---

### Third-party Script

Script de **dominio diferente** a la página.

**Ejemplos comunes:**

- Analytics: `https://www.google-analytics.com/analytics.js`
- Ads: `https://securepubads.g.doubleclick.net/tag/js/gpt.js`
- CDN: `https://cdn.jsdelivr.net/npm/library@1.0.0/dist/bundle.js`

**Estadística:** Los third-party scripts tienen un impacto significativo en performance, bloqueando el main thread en hasta 90% de páginas móviles. <a href="https://almanac.httparchive.org/en/2022/third-parties#performance-impact" target="_blank" rel="noopener">Fuente: HTTP Archive Web Almanac 2022</a>

---

### Inline Script

Código JavaScript dentro de `<script>` **sin atributo `src`**.

```html
<script>
  console.log("Inline script");
</script>
```

**En LoAF:** `sourceURL` estará vacío o será el URL de la página.

---

### External Script

Código JavaScript cargado desde **archivo externo** vía `<script src="">`.

```html
<script src="/app.js"></script>
```

---

### Minified Code

Código comprimido eliminando espacios, comentarios, y renombrando variables.

**Ejemplo:**

```javascript
// Original
function calculateTotalPrice(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// Minificado
function a(b) {
  return b.reduce((c, d) => c + d.price, 0);
}
```

**Impacto en LoAF:** `sourceFunctionName` será críptico (`a`, `b`, `Hc`).

---

### Source Maps

Archivos que mapean **código minificado a código original** para debugging.

**Formato:** `app.min.js.map`

**En DevTools:** Permite ver código original incluso con bundle minificado.

**Limitación con LoAF:** La API nativa de LoAF **NO** procesa Source Maps automáticamente. En producción devuelve nombres minificados (`sourceFunctionName: "a"`). Solo DevTools correlaciona Source Maps para mostrar nombres originales cuando está disponible.

**Workaround para RUM:** Herramientas como Sentry pueden procesar Source Maps del lado servidor para mapear stack traces de LoAF a código original.

---

## Herramientas

### DevTools Performance Panel

Panel de Chrome DevTools para grabar y analizar performance con flamegraphs, timeline, y métricas.

**Acceso:**

- **Windows/Linux:** `F12` o `Ctrl+Shift+I` → Performance tab
- **macOS:** `Cmd+Option+I` → Performance tab

---

### Lighthouse

Herramienta de **auditoría automatizada** de Google. Mide performance, accessibility, SEO, best practices.

**Acceso:**

- Chrome DevTools → Lighthouse tab
- CLI: `npm install -g lighthouse`
- CI/CD: Lighthouse CI

**Métricas:**

- Performance Score (0-100)
- Core Web Vitals (LCP, CLS, TBT)
- Opportunities y Diagnostics

---

### WebPageTest

Herramienta online para testing de performance con **dispositivos reales** y múltiples ubicaciones.

**URL:** <a href="https://www.webpagetest.org/" target="_blank" rel="noopener">webpagetest.org</a>

**Ventajas:**

- Testing desde dispositivos reales
- Múltiples ubicaciones geográficas
- Filmstrip view, waterfall, etc.

---

### Chrome User Experience Report (CrUX)

Dataset público con **métricas de usuarios reales** de Chrome (field data).

**Acceso:**

- <a href="https://g.co/chromeuxdash" target="_blank" rel="noopener">CrUX Dashboard</a>
- BigQuery: `chrome-ux-report.*`
- PageSpeed Insights API

---

### Web Vitals Extension

Extension de Chrome que muestra **Core Web Vitals en tiempo real** en un HUD overlay.

**Instalación:** <a href="https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma" target="_blank" rel="noopener">Chrome Web Store</a>

---

## Referencias Rápidas

### Umbrales Críticos

#### Core Web Vitals (Umbrales Oficiales de Google)

| Métrica | Good   | Needs Improvement | Poor   | Fuente                                                                                |
| ------- | ------ | ----------------- | ------ | ------------------------------------------------------------------------------------- |
| **INP** | ≤200ms | 200-500ms         | >500ms | <a href="https://web.dev/articles/inp" target="_blank" rel="noopener">web.dev/inp</a> |
| **LCP** | ≤2.5s  | 2.5-4s            | >4s    | <a href="https://web.dev/articles/lcp" target="_blank" rel="noopener">web.dev/lcp</a> |
| **CLS** | ≤0.1   | 0.1-0.25          | >0.25  | <a href="https://web.dev/articles/cls" target="_blank" rel="noopener">web.dev/cls</a> |

#### Lighthouse Metrics (Métricas Sintéticas)

| Métrica | Good   | Needs Improvement | Poor   |
| ------- | ------ | ----------------- | ------ |
| **TBT** | ≤200ms | 200-600ms         | >600ms |

#### LoAF Frames (Recomendaciones Prácticas - No Oficiales)

> ⚠️ **Nota:** Los siguientes umbrales son **recomendaciones prácticas** para clasificar frames de LoAF, **no son métricas oficiales de Google**. Usa estos valores como guía para priorizar optimizaciones.

| Concepto              | Good  | Medium   | High      | Critical |
| --------------------- | ----- | -------- | --------- | -------- |
| **Frame duration**    | ≤50ms | 50-100ms | 100-200ms | >200ms   |
| **Blocking duration** | 0ms   | <50ms    | 50-100ms  | >100ms   |

**Justificación de umbrales de frame:**

- **≤50ms:** No se considera "long frame" por LoAF (umbral mínimo)
- **50-100ms:** Frame lento pero manejable (~1-2 frames a 60fps)
- **100-200ms:** Frame lento que puede contribuir a INP >200ms
- **>200ms:** Frame crítico, puede causar INP poor por sí solo

---

### Compatibilidad

| API                     | Chrome  | Edge    | Firefox | Safari |
| ----------------------- | ------- | ------- | ------- | ------ |
| **LoAF**                | 116+ ✅ | 116+ ✅ | ❌      | ❌     |
| **Long Tasks**          | 58+ ✅  | 79+ ✅  | ❌      | ❌     |
| **Event Timing**        | 76+ ✅  | 79+ ✅  | 89+ ✅  | ❌     |
| **PerformanceObserver** | 52+ ✅  | 79+ ✅  | 57+ ✅  | 11+ ✅ |

**Cobertura LoAF:** ~82% usuarios globales (Chrome + Edge)

---

### APIs Relacionadas (Cronología)

| Año  | API                           | Propósito                |
| ---- | ----------------------------- | ------------------------ |
| 2012 | Navigation Timing             | Métricas de navegación   |
| 2013 | Resource Timing               | Timing de recursos       |
| 2015 | User Timing                   | Custom marks y measures  |
| 2017 | **Long Tasks API**            | Detectar tareas >50ms    |
| 2019 | Event Timing                  | Latencia de eventos      |
| 2019 | Layout Instability            | Medir CLS                |
| 2019 | Largest Contentful Paint      | Medir LCP                |
| 2023 | **Long Animation Frames API** | Attribution detallada ⭐ |

---

## Recursos de Aprendizaje

### Documentación Oficial

- <a href="https://developer.chrome.com/docs/web-platform/long-animation-frames" target="_blank" rel="noopener">Chrome Docs: LoAF</a>
- <a href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceLongAnimationFrameTiming" target="_blank" rel="noopener">MDN: PerformanceLongAnimationFrameTiming</a>
- <a href="https://w3c.github.io/long-animation-frames/" target="_blank" rel="noopener">W3C: Long Animation Frames Spec</a>
- <a href="https://web.dev/optimize-inp/" target="_blank" rel="noopener">Web.dev: Optimize INP</a>

### Artículos y Guías

- <a href="https://www.debugbear.com/blog/long-animation-frames" target="_blank" rel="noopener">DebugBear: Measuring Long Animation Frames</a>
- <a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance_API" target="_blank" rel="noopener">MDN: Performance API</a>
- <a href="https://www.speedcurve.com/blog/guide-long-animation-frames-loaf/" target="_blank" rel="noopener">The Definitive Guide to Long Animation Frames (LoAF)</a>
- <a href="https://web.dev/vitals/" target="_blank" rel="noopener">Web.dev: Core Web Vitals</a>
- <a href="https://web.dev/user-centric-performance-metrics/" target="_blank" rel="noopener">Web.dev: User-centric performance metrics</a>

### Herramientas y Recursos

- <a href="https://caniuse.com/mdn-api_performancelonganimationframetiming" target="_blank" rel="noopener">Can I Use: LoAF</a>
- <a href="https://gist.github.com/paulirish/5d52fb081b3570c81e3a" target="_blank" rel="noopener">Paul Irish: What forces layout</a>
- <a href="https://github.com/andydavies/perf-timeline-to-devtools-profile" target="_blank" rel="noopener">Creates custom DevTools Performance Panel populated with entries from the Performance Timeline</a>

### Casos de Éxito

**Taboola: Optimización de INP con técnicas avanzadas**

- **Caso:** <a href="https://web.dev/case-studies/taboola-inp?hl=es_419" target="_blank" rel="noopener">Cómo Taboola redujo INP en un 50%</a>
- **Contexto:** Plataforma de contenido web optimizando interacciones en widgets
- **Estrategias:** Análisis profundo de long tasks, optimización de event handlers, mejoras en rendering
- **Impacto:** Reducción del 50% en INP y mejoras significativas en user engagement

**Recursos adicionales de casos reales:**

- <a href="https://web.dev/case-studies/" target="_blank" rel="noopener">Web.dev Case Studies</a> - Colección de casos reales de optimización
- <a href="https://developers.google.com/web/showcase" target="_blank" rel="noopener">Google Developers Showcase</a> - Ejemplos de implementaciones exitosas
- <a href="https://speedcurve.com/blog/tag/case-study/" target="_blank" rel="noopener">SpeedCurve Case Studies</a> - Análisis de performance en sitios reales

---

<!--📚 [Volver a la serie de artículos](./README.md)-->
