Manejador de eventos pesado: por qué un clic tarda 500 ms y cómo solucionarlo
Qué ocurre
Cuando un usuario hace clic, el navegador ejecuta tu manejador de eventos por completo antes de poder pintar el siguiente frame. Si el manejador realiza cientos de milisegundos de trabajo síncrono — filtrar un array grande, construir DOM, parsear JSON — la página queda congelada exactamente ese tiempo. El usuario no ve nada hasta que el manejador retorna.
Es el problema de INP más común y aparece en el desglose de INP como una fase larga de processing time.
Cómo reconocerlo
- El processing time domina el desglose de INP (input delay y presentation delay son pequeños).
- En DevTools Performance, una tarea larga empieza justo en el evento y se atribuye a tu función manejadora.
- La lentitud escala con el tamaño de los datos: cuantas más filas/elementos, peor se siente el clic.
Cómo solucionarlo
- Actualiza la UI primero (estado pulsado, spinner), luego cede el control al navegador con scheduler.yield() (o setTimeout(0) como alternativa) antes de hacer el trabajo pesado.
- Divide los bucles grandes en trozos, cediendo el control entre ellos para que el navegador pueda pintar.
- Mueve el cálculo puro (parseo, filtrado, diffing) a un Web Worker — el hilo principal solo envía la entrada y recibe el resultado.
Problema
button.addEventListener("click", () => {
const results = filterRows(allRows) // 400 ms of sync work
renderTable(results) // user saw nothing until now
})
Solución
button.addEventListener("click", async () => {
button.classList.add("loading") // instant feedback, painted first
await scheduler.yield() // let the browser paint
const results = filterRows(allRows)
renderTable(results)
button.classList.remove("loading")
})
Escanea tu sitio gratis →