No todos los frames lentos son iguales
Un frame de 51ms es técnicamente "lento", pero no es tan crítico como uno de 300ms. Necesitamos categorizar los frames por severidad para priorizar qué optimizar.
En este ejemplo aprenderemos a filtrar y categorizar frames usando
blockingDuration.
Niveles de severidad
| Nivel | Blocking Duration | Impacto | Acción |
|---|---|---|---|
| 🔴 Crítico | > 200ms | Muy malo para INP | Optimizar urgentemente |
| 🟡 Alto | 100ms - 200ms | Problemático | Priorizar optimización |
| 🔵 Medio | 50ms - 100ms | Aceptable, mejorable | Revisar si hay tiempo |
Demo interactiva
📊 Frames detectados:
🔴 Críticos: 0 |
🟡 Altos: 0 |
🔵 Medios: 0
Últimos frames detectados:
Código del filtrado
Función de categorización
function getFrameSeverity(blockingDuration) {
if (blockingDuration > 200) {
return {
level: 'critical',
label: 'Crítico',
color: '#d32f2f',
icon: '🔴'
};
}
if (blockingDuration > 100) {
return {
level: 'high',
label: 'Alto',
color: '#f57c00',
icon: '🟡'
};
}
if (blockingDuration > 50) {
return {
level: 'medium',
label: 'Medio',
color: '#1a73e8',
icon: '🔵'
};
}
return {
level: 'low',
label: 'Bajo',
color: '#388e3c',
icon: '🟢'
};
}
Usar el filtro en el observer
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const severity = getFrameSeverity(entry.blockingDuration);
// Solo loggear frames críticos
if (severity.level === 'critical') {
console.error('Frame crítico detectado!', entry);
sendToMonitoring(entry); // Enviar a sistema de alertas
}
// O loggear solo frames alto/crítico
if (severity.level === 'critical' || severity.level === 'high') {
console.warn(\`Frame \${severity.label}:\`, entry);
}
}
});
Estrategias de filtrado
1. Filtrar por umbral mínimo
// Solo procesar frames muy problemáticos
const CRITICAL_THRESHOLD = 200;
observer.observe((list) => {
for (const entry of list.getEntries()) {
if (entry.blockingDuration > CRITICAL_THRESHOLD) {
handleCriticalFrame(entry);
}
}
});
2. Diferentes acciones por severidad
const severity = getFrameSeverity(entry.blockingDuration);
switch (severity.level) {
case 'critical':
// Alertar inmediatamente
sendAlert(entry);
logToServer(entry);
break;
case 'high':
// Loggear para revisión
logToServer(entry);
break;
case 'medium':
// Solo en desarrollo
if (isDevelopment) {
console.log('Frame medio:', entry);
}
break;
}
3. Sampling en producción
// Solo enviar 10% de frames medios a analytics
const severity = getFrameSeverity(entry.blockingDuration);
if (severity.level === 'critical') {
sendToAnalytics(entry); // Siempre
} else if (severity.level === 'high') {
sendToAnalytics(entry); // Siempre
} else if (severity.level === 'medium' && Math.random() < 0.1) {
sendToAnalytics(entry); // 10% de las veces
}
⚠️ En producción:
Usa sampling para frames de baja severidad para evitar sobrecarga de datos. Los frames críticos siempre deben capturarse al 100%.
¿Por qué usar blockingDuration?
blockingDuration es más útil que duration porque:
- duration: Tiempo total del frame (incluye los primeros 50ms "aceptables")
-
blockingDuration: Tiempo que realmente bloquea la UI (
duration - 50ms)
// Ejemplo
entry.duration = 234ms
entry.blockingDuration = 184ms // 234 - 50 = 184ms de bloqueo real
El blockingDuration refleja mejor el impacto real en la
experiencia del usuario.