⌘ REFERENCIA · 193 elementos
Cheatsheet de Rendimiento Web
Las tres fases enteras en un sitio: métricas y umbrales, red y caché, el coste del JavaScript, el hilo principal, el pipeline de píxeles, memoria y estrategias de carga. Busca por métrica o por síntoma.
📊 Core Web Vitals 13
Cuándo se pinta el mayor elemento con contenido de la ventanaLCP
Bueno hasta 2,5 s; malo por encima de 4 sUmbral de LCP
La latencia de las interacciones de la visita, no de un clicINP
Bueno hasta 200 ms; malo por encima de 500 msUmbral de INP
La mayor ráfaga de desplazamiento, no la suma de la páginaCLS
Bueno hasta 0,1; malo por encima de 0,25Umbral de CLS
Al 95 bastan 5 visitas raras de 100 para decidirloPercentil 75
Menos de 1 s entre saltos y 5 s de duración máximaVentana de sesión
Fracción de impacto por fracción de distanciaPuntuación de un salto
Se tira la peor interacción por cada cincuentaDescarte del INP
Un svg completo no lo es; una imagen dentro de él síCandidatos a LCP
El menor entre el visible y el intrínsecoTamaño que compite
Scroll, hover y zoom quedan fuera del INPLa zona ciega
🔬 Campo y laboratorio 11
Qué les pasó a tus usuarios; no dice por quéCampo
Por qué pasa, en unas condiciones que no existenLaboratorio
Media móvil de 28 días: un despliegue tarda ese mes en verseCrUX
Origen indexable y sobre un umbral que no se publicaElegibilidad
Se tiran query y fragmento, aunque distingan páginasNormalización de URL
Limitación simulada: reproducible, no fiel al dispositivoLighthouse
No se puede: necesita las tareas por debajo de 50 msTBT en campo
El build de atribución convierte la métrica en una causaweb-vitals
Enviar en visibilitychange, nunca en unloadsendBeacon
La media junta el escritorio bueno con el móvil maloSegmentar
Decide el campo; el laboratorio explica y protegeCuál manda
🌐 Red, HTTP y QUIC 11
Duplicar el ancho de banda casi no mueve la cargaLa latencia manda
Cada ida y vuelta se paga aunque no viaje ningún byte útilRTT
DNS, TCP y TLS antes del primer byte de respuestaAnatomía de la petición
Ventana inicial de 10 segmentos que dobla en cada rondaSlow start
Lo que cabe en la primera ronda; es un cálculo, no una constanteLos 14 KB
Una respuesta por conexión: bloqueo de cabecera de líneaHTTP/1.1
Multiplexa flujos, pero el bloqueo baja un nivel, a TCPHTTP/2
Sobre UDP: flujos independientes y pérdida aisladaQUIC
HTTP sobre QUIC, con el saludo fundido con el de TLSHTTP/3
Datos en el primer paquete a cambio de riesgo de repetición0-RTT
Cuenta las idas y vueltas antes de contar los bytesPresupuesto de viajes
🗄️ Caché HTTP y compresión 16
La única directiva que significa de verdad no guardes estono-store
Sí se guarda: obliga a revalidar antes de cada usono-cache
Solo la caché del usuario, nunca una compartidaprivate
Segundos de frescura desde que se generó la respuestamax-age
Solo cachés compartidas, y con precedencia en ellass-maxage
Rancia y sin red: mejor un error que contenido viejomust-revalidate
Solo con URL única por contenido; si no, es irreversibleimmutable
Sirve lo rancio y refresca por detrás: nadie esperastale-while-revalidate
La copia vieja como red de seguridad ante un fallostale-if-error
Revalidar con If-None-Match y cobrar un 304 sin cuerpoETag
Cada dimensión que añades multiplica las entradas de cachéVary
Un año en el estático y el HTML sin caché que lo apuntaNombre con hash
Diccionario web incorporado: gana más en ficheros pequeñosBrotli
Ratio parecido a Brotli descomprimiendo mucho más rápidoZstandard
Al máximo nivel en el build, no en cada peticiónCompresión estática
Imágenes, vídeo y woff2 no ganan nada y cuestan CPULo ya comprimido
🚧 Ruta crítica y pistas 15
No se pinta nada hasta tener el CSSOM completoCSS bloqueante
Para el parser y además espera al CSS que tenga delanteJS bloqueante
Descarga en paralelo, ejecuta al final y en ordendefer
Ejecuta en cuanto llega: sin orden garantizadoasync
Diferido por defecto, y con su propio grafo que descubrirtype="module"
Lee el HTML en bruto y adelanta descargas antes del DOMPreload scanner
Lo que solo existe en JS o en data-src es invisible para élCegarlo
Con as, y crossorigin en fuentes, o se descarga dos vecespreload
Adelanta DNS, TCP y TLS; tres o cuatro orígenes como muchopreconnect
Solo resuelve el nombre: barato, para lo que quizá usesdns-prefetch
Deja el módulo parseado en el mapa, no bytes en una cachémodulepreload
No es Baseline, y la partición lo limita a tu propio sitioprefetch
De un solo motor: cuéntalo para esa fracción de usuariosReglas de especulación
Sube o baja la prioridad dentro del mismo tipo de recursofetchpriority
Nadie crea ancho de banda: adelantar algo retrasa otra cosaEl preload que daña
🖼️ LCP e imágenes 15
Sin solape ni hueco: suman el LCP enteroLas cuatro subpartes
En torno al 40 por ciento en una página sanaTTFB
Menos del 10 por ciento; si sube, es descubrimientoRetraso de carga
En torno al 40 por ciento: tamaño, formato y distanciaDuración de la carga
Menos del 10 por ciento: bloqueo de render e hilo ocupadoRetraso de renderizado
Solo unos respecto a otros; no los pases a milisegundosLeer el reparto
El navegador no compara pesos: tu orden es el rankingOrden en picture
Un tipo desconocido descarta la fuente sin costetype en source
Declara qué es cada fichero, no cuándo hay que usarlosrcset con w
Densidad y solo densidad; sin descriptor equivale a 1xsrcset con x
Promesa sobre el ancho que ocupará; si falta se asume 100vwsizes
Nunca sobre el elemento LCP; su umbral es de más de mil píxelesloading="lazy"
Donde paga es al insertar imágenes durante una interaccióndecoding="async"
Para el hero, si el panel de red no lo prioriza ya solofetchpriority="high"
Color dominante o LQIP, con el espacio ya reservadoPlaceholder
📜 El coste del JavaScript 10
Descarga, parseo, compilación y ejecuciónLas cuatro fases
El mismo peso cuesta mucho más porque hay que ejecutarloJS frente a imagen
El motor pospone lo que cree que no vas a llamarCompilación perezosa
La segunda visita se ahorra compilar, y la tercera másCaché de código
Varias veces más lento que tu portátil con el mismo bundleEl móvil de tus usuarios
Un número acordado que rompe el build, no una aspiraciónPresupuesto
Mira el peso tras comprimir y por ruta, no el total en discoAnalizar el bundle
Sustituir, importar el submódulo o cargarla bajo demandaLa dependencia gorda
Servidas al navegador moderno que hace años que no las necesitaPolyfills
Compilar hacia atrás infla el código y lo hace más lentoObjetivo moderno
🌳 Splitting y tree shaking 10
El punto de corte que el empaquetador convierte en chunkimport() dinámico
El primer corte y el que más rindeDividir por ruta
Cargar cuando el usuario demuestra intenciónDividir por interacción
En el hover o en tiempo ocioso, antes del clicPrecargar el chunk
Cada nivel de descubrimiento es un viaje en serieCascada de peticiones
CommonJS se resuelve al ejecutar: no hay nada que recortarDepende de ESM
La promesa que permite borrar un módulo enterosideEffects
Un index que reexporta todo suele arrastrarlo todoFicheros barril
Efectos en el nivel superior, defineProperty y las clasesLo que rompe el recorte
Busca el símbolo en la salida en vez de suponer que se fueVerificar
🧵 El hilo principal 12
Más de 50 ms de hilo ocupado sin devolver el controlLong task
Repartir los 100 ms de respuesta entre esperar y trabajarDe dónde salen los 50
Suma del exceso de cada tarea por encima de 50 msTBT
Bueno bajo 200 ms, malo por encima de 600 en móvil emuladoUmbrales del TBT
Cinco tareas de 45 ms no generan ninguna entradaEl punto ciego
Desglose por script del fotograma lento; solo Chromiumlong-animation-frame
Cede y la continuación vuelve por delante de lo normalscheduler.yield()
Reciente y sin Safari: la degradación no es opcionalSu soporte
Tres prioridades explícitas para tu propio trabajoscheduler.postTask()
Ceder solo cuando de verdad hay alguien esperandoisInputPending()
Al final de la cola, detrás de los temporizadores ajenossetTimeout de cero
De 400 a cuatro de 100 ya quita casi todo el dañoTrocear
⚙️ INP y workers 12
El hilo estaba ocupado cuando el usuario actuóRetraso de entrada
Desde el primer manejador hasta que acaba el últimoDuración del procesamiento
Estilo, layout, pintura y composición del fotogramaRetraso de presentación
El selector que convierte el número en un botón concretointeractionTarget
Pinta el cambio visual y cede antes del trabajo pesadoSeparar la respuesta
Trocear un bucle no arregla el retraso de presentaciónLa asignación es estricta
Cómputo puro, sin DOM y con poca conversaciónQué mover al worker
Clonado estructurado: el coste crece con el tamaño del datopostMessage
Pasar la propiedad del búfer en vez de copiarloTransferibles
Exige aislamiento de origen cruzado con COOP y COEPSharedArrayBuffer
Llamadas con await en lugar de escribir la plomeríaComlink
Si toca el DOM o si el trabajo cabe en unos milisegundosCuándo no compensa
📐 CLS y fuentes 13
width y height en el marcado más aspect-ratio en el CSSReservar espacio
Banners y avisos que empujan lo que ya se estaba leyendoContenido inyectado
transform y opacity no mueven a los vecinosAnimar sin desplazar
La entrada trae los elementos inestables de cada ráfagaAtribuir el salto
La reserva y la definitiva no ocupan lo mismoLa fuente que salta
3 s invisible y luego intercambia igualmentefont-display: block
Reserva a los 100 ms e intercambia siempre: garantiza el saltofont-display: swap
Reserva a los 100 ms y solo intercambia si llega prontofont-display: fallback
Cero intercambio en esta carga, luego cero desplazamientofont-display: optional
Se comporta como block: hasta 3 s de texto invisibleauto no es neutro
Que la reserva ocupe exactamente lo mismo que la realsize-adjust
Con crossorigin, y junto a optional sube mucho el aciertoPrecargar la fuente
Trozos que solo se descargan si aparece uno de sus glifosunicode-range
🎞️ Pipeline de píxeles y layout 13
Estilo, layout, pre-paint, pintura, rasterizado y composiciónLas etapas
Cuesta por elemento reevaluado, no por propiedad que tocasteRecálculo de estilo
Cambiar geometría recorre todas las etapas del hiloEl camino completo
transform y opacity los resuelve el compositor con la texturaSolo composición
Esa animación sigue fluida con el hilo principal bloqueadoLa ventaja real
Leer geometría tras escribir obliga a rehacer el layoutLayout síncrono forzado
Todas las lecturas antes de la primera escrituraLeer y luego escribir
Muchas veces la salida es no necesitar la medida, no medir mejorNo medir
Lo de dentro no altera el layout de fueracontain: layout
Recorta de verdad: adiós sombras, tooltips y desplegablescontain: paint
Se dimensiona como si estuviera vacío y colapsa a cerocontain: size
Se salta el renderizado de lo que no está a la vistacontent-visibility: auto
La altura supuesta: sin ella la barra de scroll bailacontain-intrinsic-size
🧠 Listas grandes y memoria 10
Estilo, layout, pintura y árbol de accesibilidad, por cada unoEl coste de un nodo
Montar solo la ventana visible más un margen de seguridadVirtualización
Estimar y corregir; de ahí el scroll que da tironesAlturas variables
Paginar, filtrar o content-visibility suelen bastarAntes de virtualizar
Rompe el pie de página, el enlace profundo y el volver atrásScroll infinito
Memoria que ya no se usa y sigue siendo alcanzableQué es una fuga
Antes, después de actuar y tras deshacer: lo que queda sobraTres snapshots
Fuera del DOM y retenidos por una referencia en JSNodos desprendidos
Un oyente que no se quita retiene todo lo que capturóListeners y cierres
Medir en producción; exige aislamiento de origen cruzadomeasureUserAgentSpecificMemory
🏗️ Estrategias de render 11
HTML en el build: el mejor TTFB y el peor tiempo de publicaciónSSG
HTML por petición: fresco, con el servidor en la ruta críticaSSR
Generar una vez y revalidar por caducidad o bajo demandaISR
HTML vacío: el LCP espera a que el JavaScript termineCSR
Manda la cabecera antes de tener los datos del cuerpoStreaming de HTML
Se ve pero no responde: el peor tramo del INPEl impuesto de hidratar
El cliente reconstruye el árbol que el servidor ya construyóPor qué es caro
JavaScript como excepción declarada, no como normaIslas
Hidratar menos, y lo que se hidrate en mejor ordenHidratación parcial
Disparadores: visible, ocioso, interacción, medio, nuncaHidratación progresiva
Serializar los cierres y continuar sin ejecutar el árbolResumibilidad
🛰️ Service workers, edge y terceros 13
install, waiting y activate: el nuevo espera al viejoCiclo de vida
Cambias el worker debajo de una página que esperaba al anteriorskipWaiting
La única correcta para ficheros con hash en el nombreCache first
Sin tiempo límite, una red mala es peor que no tener redNetwork first
La opción por defecto para lo que no es crítico ni tiene hashStale while revalidate
El cuerpo se consume una vez: clona antes de leer nadaresponse.clone()
Reservan cuota inflada aunque el recurso pese pocoRespuestas opacas
Un worker mal desplegado se queda: ten el interruptor listoVía de escape
Método, esquema, host, ruta, query y lo que añada VaryClave de caché
Cada dimensión que añades divide la tasa de aciertosCardinalidad
Cinco partidas, y los bytes suelen ser la más pequeñaCoste de un tercero
Pinta el marcador y carga el widget solo si lo tocanPatrón de fachada
Gana con cómputo propio y pierde en cada acceso al DOMPartytown
🤖 Rendimiento en CI 8
Cinco pasadas y no tres: con tres la mediana sigue bailandoLighthouse CI
En CI quieres comparabilidad, no fidelidad al dispositivoLimitación simulada
Un instrumento de medida con la CPU de otro trabajo encimaEjecutor compartido
Falla el build solo sobre métricas deterministasPresupuestos
Que traiga el diagnóstico, no el síntoma con un númeroEl mensaje de error
Documentada y con caducidad, o alguien quita la puertaVía de excepción
Cuántos KB creció y qué dependencia los trajoDiff del bundle
Lo determinista en el PR; el dispositivo real de madrugadaCada commit y cada noche