Тяжёлый обработчик события: почему клик занимает 500 мс и как это починить
Что происходит
Когда пользователь кликает, браузер выполняет обработчик события до конца, прежде чем сможет отрисовать следующий кадр. Если обработчик делает сотни миллисекунд синхронной работы — фильтрует большой массив, строит DOM, парсит JSON — страница заморожена ровно на это время. Пользователь не видит никакой реакции, пока обработчик не вернётся.
Это самая частая проблема INP; в разбивке INP она видна как длинная фаза processing time.
Как распознать
- Processing time доминирует в разбивке INP (input delay и presentation delay малы).
- В DevTools Performance одна длинная задача начинается прямо на событии и атрибутируется вашей функции-обработчику.
- Тормоза растут с объёмом данных: чем больше строк/элементов, тем хуже ощущается клик.
Как починить
- Сначала обновите UI (нажатое состояние, спиннер), затем отдайте управление браузеру через scheduler.yield() (или setTimeout(0) как фоллбэк) — и только потом делайте тяжёлую работу.
- Разбейте большие циклы на части, отдавая управление между частями, чтобы браузер успел отрисовать кадр.
- Вынесите чистые вычисления (парсинг, фильтрацию, диффы) в Web Worker — главный поток только отправляет вход и получает результат.
Проблема
button.addEventListener("click", () => {
const results = filterRows(allRows) // 400 ms of sync work
renderTable(results) // user saw nothing until now
})
Фикс
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")
})
Просканировать свой сайт бесплатно →