Снижение INP: оптимизация обработчиков событий
Устраняйте дребезг тяжёлых обработчиков, используйте scheduler.yield() и избегайте долгих задач, блокирующих главный поток.
«Снижение INP: оптимизация обработчиков событий» — бесплатный урок React Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.
Что такое INP?
Взаимодействие до следующей отрисовки (INP) измеряет задержку от действия пользователя (щелчка, касания или нажатия клавиши) до момента, когда браузер отрисует ответ. При INP > 200ms интерфейс кажется медленным.
Почему события React могут обрабатываться медленно
Обработчики событий React, выполняющие слишком много работы синхронно, блокируют основной поток. Браузер не может отрисовать ответ, пока не завершится задача JS, из-за чего INP становится высоким.
Устранение частых вызовов при вводе
Откладывайте ресурсоёмкие операции (вызовы API поиска, сложные вычисления), запускаемые при нажатии клавиш. Обновлять состояние React при каждом нажатии клавиши нормально; откладывать следует именно ресурсоёмкую работу.
import { useDeferredValue, useState } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query); // defers re-render of slow parts
return (
<>
<input value={query} onChange={e => setQuery(e.target.value)} />
<SearchResults query={deferredQuery} /> {/* re-renders with lower priority */}
</>
);
}useTransition для несрочных обновлений
Оборачивайте медленные обновления состояния в startTransition, чтобы пометить их как несрочные. React откладывает их, сохраняя отзывчивость ввода.
const [isPending, startTransition] = useTransition();
function handleFilter(value) {
setInputValue(value); // urgent — update input immediately
startTransition(() => {
setFilteredList(expensiveFilter(value)); // non-urgent — can be interrupted
});
}Перенос ресурсоёмкой работы из основного потока
Используйте веб-воркеры для задач, требующих значительных ресурсов CPU (разбора больших наборов данных, обработки изображений). Основной поток остаётся отзывчивым, пока вычисления выполняются в воркере.
const worker = new Worker(new URL('./heavy-worker.js', import.meta.url));
function processData(data) {
return new Promise(resolve => {
worker.postMessage(data);
worker.onmessage = e => resolve(e.data);
});
}
// In component:
const handleClick = async () => {
const result = await processData(largeDataset); // doesn't block main thread
setResult(result);
};Как избегать длительных задач
Длительные задачи (>50ms) блокируют основной поток и увеличивают INP. Разбивайте их с помощью setTimeout, scheduler.yield() или requestIdleCallback.
async function processInChunks(items) {
const CHUNK_SIZE = 100;
for (let i = 0; i < items.length; i += CHUNK_SIZE) {
const chunk = items.slice(i, i + CHUNK_SIZE);
processChunk(chunk);
await new Promise(r => setTimeout(r, 0)); // yield to browser between chunks
}
}scheduler.yield() (современный API)
scheduler.yield() возвращает управление циклу событий браузера, позволяя обработать ожидающие действия пользователя до возобновления вашего кода.
async function longTask() {
for (const item of largeList) {
processItem(item);
if (/* every N items */) {
await scheduler.yield(); // let browser handle pending clicks/inputs
}
}
}Избегайте синхронной разметки в обработчиках
Чтение свойств разметки (offsetWidth, getBoundingClientRect()) принудительно запускает синхронный пересчёт разметки. Группируйте чтение перед записью, чтобы избежать многократной переработки разметки.
// Bad — forces layout recalculation on each iteration:
items.forEach(item => {
const height = item.offsetHeight; // READ — forces layout
item.style.height = height * 2 + 'px'; // WRITE — dirties layout
});
// Good — batch reads, then writes:
const heights = items.map(item => item.offsetHeight); // all reads
heights.forEach((h, i) => items[i].style.height = h * 2 + 'px'); // all writesДействия React 19 для асинхронного INP
Действия React 19 обрабатывают асинхронные изменения данных, не блокируя интерфейс: состояние ожидания обновляется независимо, поэтому страница остаётся интерактивной.
function LikeButton({ postId }) {
const [optimistic, setOptimistic] = useOptimistic(false);
async function handleLike() {
setOptimistic(true);
await likePost(postId); // async — doesn't block
}
return <button onClick={handleLike}>{optimistic ? 'Liked' : 'Like'}</button>;
}Подводные камни делегирования событий
React использует делегирование синтетических событий (добавляет один обработчик к корневому элементу). Не добавляйте сотни отдельных обработчиков событий DOM в useEffect — вместо этого используйте синтетические события React в элементах JSX.
Измерение INP в DevTools
Используйте панель Performance в Chrome DevTools, чтобы записать взаимодействие и изучить длительные задачи. Ищите записи «Interaction» на временной шкале и раскрывайте их, чтобы найти блокирующее выполнение скриптов.
Быстрая проверка
Какой хук React помечает обновление состояния как несрочное, чтобы его можно было прервать действиями пользователя?
Итоги
Уменьшайте INP, откладывая ресурсоёмкую работу, используя startTransition для несрочных обновлений, перенося вычисления CPU в веб-воркеры и разбивая длительные задачи с помощью scheduler.yield(). Группируйте чтение DOM перед записью, чтобы избежать многократной переработки разметки.
Часто задаваемые вопросы
Урок «Снижение INP: оптимизация обработчиков событий» бесплатный?
Да — полный текст урока «Снижение INP: оптимизация обработчиков событий» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.
Чему я научусь в уроке «Снижение INP: оптимизация обработчиков событий»?
Устраняйте дребезг тяжёлых обработчиков, используйте scheduler.yield() и избегайте долгих задач, блокирующих главный поток. Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать React Academy?
Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Снижение INP: оптимизация обработчиков событий»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке React Academy?
Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Измерение основных веб-показателей в приложениях React
- Анализ сборки и стратегия разделения кода
- Оптимизация изображений и шрифтов в React
- Снижение INP: оптимизация обработчиков событий