Manipulador de eventos pesado: por que um clique leva 500 ms e como corrigir
O que acontece
Quando um usuário clica, o navegador executa seu manipulador de eventos até o fim antes de poder pintar o próximo frame. Se o manipulador faz centenas de milissegundos de trabalho síncrono — filtrar um array grande, construir DOM, parsear JSON — a página fica congelada exatamente por esse tempo. O usuário não vê nada até o manipulador retornar.
É o problema de INP mais comum e aparece no detalhamento do INP como uma longa fase de processing time.
Como reconhecer
- O processing time domina o detalhamento do INP (input delay e presentation delay são pequenos).
- No DevTools Performance, uma tarefa longa começa logo no evento e é atribuída à sua função manipuladora.
- A lentidão cresce com o tamanho dos dados: quanto mais linhas/itens, pior o clique parece.
Como corrigir
- Atualize a UI primeiro (estado pressionado, spinner), depois ceda o controle ao navegador com scheduler.yield() (ou setTimeout(0) como fallback) antes de fazer o trabalho pesado.
- Divida laços grandes em partes, cedendo o controle entre elas para o navegador poder pintar.
- Mova o cálculo puro (parsing, filtragem, diffing) para um Web Worker — a thread principal só envia a entrada e recebe o resultado.
Problema
button.addEventListener("click", () => {
const results = filterRows(allRows) // 400 ms of sync work
renderTable(results) // user saw nothing until now
})
Correção
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")
})
Escaneie seu site gratuitamente →