1. Pregunta
Una aplicación de página única con acceso global necesita datos de rendimiento de usuarios reales para comparar experiencias entre dispositivos, redes y versiones. Recopile datos de LCP, carga de recursos y tareas largas limitando al mismo tiempo los reportes por sesión de página. Diseñe un recolector PerformanceObserver y explique cómo maneja las entradas creadas antes del registro del observer, la pérdida de búfer, los recursos de cross-origin y los cambios de ruta en la SPA.
2. Restricciones y aclaraciones
- Defina el alcance temporal de cada métrica: documento inicial, navegación suave (soft navigation) o una sesión completa.
- Establezca una tasa de muestreo, un límite de entradas por tipo, un tamaño de lote y una política de reintentos ante fallas para que la recolección no afecte la página.
- Distinga las diferencias de soporte del navegador de los datos faltantes; los valores faltantes necesitan un motivo y no deben convertirse en cero.
- Defina límites de privacidad para las URL de recursos, identificadores de usuario y dimensiones de consulta; no reporte URL completas ni parámetros confidenciales directamente.
3. Conceptos clave
PerformanceObserver recibe entradas para los tipos de entrada seleccionados; buffered: true puede recuperar entradas registradas antes de que se creara el observer. Los tipos de recursos, tareas largas, pintura (paint) y LCP tienen límites de búfer, y la devolución de llamada (callback) puede recibir droppedEntriesCount para revelar las entradas descartadas debido a que el búfer estaba lleno. LCP es el tiempo de renderizado de la imagen o bloque de texto más grande durante la carga; después de la interacción del usuario, el contenido posterior no debe tratarse como el LCP inicial. Sin un encabezado de respuesta Timing-Allow-Origin adecuado, los datos de temporización para recursos de cross-origin pueden estar restringidos o faltar.
4. Implementación de referencia
startCollector():
session = createSessionId()
observe("largest-contentful-paint", {buffered: true})
observe("resource", {buffered: true})
observe("longtask", {buffered: true})
observe(type, options):
if type not in PerformanceObserver.supportedEntryTypes:
markUnsupported(type)
return
observer = new PerformanceObserver((list, _, dropped) =>
appendSanitized(list.getEntries())
if dropped > 0: markDropped(type, dropped)
flushWhenBatchIsReady()
)
observer.observe({type, ...options})
onSoftNavigation(route):
closePreviousView(route)
resetViewScopedMetrics()Registre un observer separado para cada tipo de entrada y utilice buffered para recuperar registros tempranos. El callback conserva solo los campos obligatorios, elimina los parámetros de URL y envía lotes. Cada vista almacena el tiempo de registro del observer, la ruta y la versión; una navegación suave cierra la vista anterior y restablece las métricas con alcance de vista. Los recuentos de recursos o errores con alcance de sesión continúan con una clave de deduplicación explícita.
5. Calidad de datos y compensaciones de costos
Un muestreo más alto estabiliza los cuantiles pero aumenta los costos de red y almacenamiento. Mantenga una muestra más alta para LCP y tareas largas, mientras aplica muestreo inicial (head-sampling) a las entradas de recursos o conserva solo los recursos lentos. Un solo búfer resource admite hasta 250 entradas de forma predeterminada, por lo que el recolector debe consumirlo durante el ciclo de vida de la página y registrar las pérdidas en lugar de aumentar indefinidamente la frecuencia de reportes. Limite los reintentos del cliente después de un fallo de lote y descarte los lotes obsoletos en la siguiente visita para que una cola local no ralentice el inicio.
6. Verificación y observabilidad
- Cree entradas antes del registro del observer para verificar
buffered; use una página con alta carga de recursos para verificar las alertas dedroppedEntriesCount. - Pruebe recursos de cross-origin con y sin
Timing-Allow-Originy confirme que los motivos de los campos faltantes sigan siendo distinguibles. - Reproduzca por separado la carga inicial, la navegación suave, la recuperación en segundo plano y el ocultamiento de la página; verifique que el LCP y las entradas de recursos no se atribuyan a múltiples vistas.
- Monitoree el uso de CPU y memoria del recolector, los bytes reportados, la tasa de fallas de lotes, la tasa de pérdida de entradas y la tasa de soporte.
7. Errores comunes
- Crear observers solo después del evento
load, perdiendo permanentemente entradas tempranas de LCP o recursos. - Ignorar silenciosamente
droppedEntriesCountmientras se trata una muestra incompleta como una distribución completa. - Tratar la temporización restringida de cross-origin como latencia cero real, corrompiendo los cuantiles de rendimiento.
- Crear un nuevo observer en cada ruta de la SPA sin cerrar el anterior, causando reportes duplicados y fugas de memoria.
8. Puntos de evaluación en entrevistas
Utiliza el ciclo de vida del observer correctamente
La respuesta debe cubrir buffered, supportedEntryTypes, el apagado del observer y los límites de la navegación suave para evitar pérdidas tempranas y atribuciones duplicadas.
Maneja los límites de búfer y cross-origin
El candidato debe monitorear droppedEntriesCount, conocer el límite del búfer de recursos y usar Timing-Allow-Origin para explicar los campos faltantes de cross-origin.
Diseña un muestreo y reporte controlados
El candidato debe asignar el muestreo, los límites de entradas y el procesamiento por lotes según el valor de la métrica y explicar por qué los reintentos no ralentizan la página.
Verifica la confiabilidad de los datos
El candidato debe cubrir las entradas tempranas, las páginas con alta carga de recursos, las temporizaciones de cross-origin, la navegación suave y la recuperación en segundo plano mientras mide la sobrecarga y la pérdida del recolector.