降低 INP:事件处理器优化
对繁重的处理器进行防抖,使用 scheduler.yield(),并避免阻塞主线程的长任务。
降低 INP:事件处理器优化 是 CoddyKit 上的免费 React Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。
什么是 INP?
交互到下一次绘制(INP)衡量从用户交互(点击、轻触、按键)开始,到 browser 绘制响应之间的延迟。INP > 200ms 时,用户会感觉页面反应迟钝。
为什么 React 事件可能很慢
如果 React 事件处理程序同步执行过多工作,就会阻塞主线程。在 JS 任务完成之前,browser 无法绘制响应,从而导致 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 的任务(解析大型数据集、图像处理)使用 Web Worker。主线程可以保持响应,同时由 worker 进行计算。
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() 会将控制权交还给 browser 的事件循环,使等待中的用户交互能够先被处理,然后再继续执行您的代码。
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 writesReact 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 使用合成事件委托(将一个监听器附加到根元素)。避免在 useEffect 中附加数百个独立的 DOM 监听器;应在 JSX 元素上使用 React 的合成事件。
在 DevTools 中测量 INP
使用 Chrome DevTools 的 Performance 面板记录一次交互并检查长任务。在时间线中查找“交互”条目,并展开它们以找出阻塞脚本执行的部分。
快速检查
哪个 React 钩子可以将状态更新标记为非紧急更新,使其能够被用户交互中断?
回顾
通过对高开销工作进行防抖、使用 startTransition 处理非紧急更新、将 CPU 工作转移到 Web Worker,以及使用 scheduler.yield() 拆分长任务来降低 INP。先批量读取 DOM,再批量写入,以避免布局抖动。
常见问题解答
「降低 INP:事件处理器优化」课时是免费的吗?
是的 — 「降低 INP:事件处理器优化」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。
「降低 INP:事件处理器优化」这节课中我会学到什么?
对繁重的处理器进行防抖,使用 scheduler.yield(),并避免阻塞主线程的长任务。 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 React Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「降低 INP:事件处理器优化」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 React Academy 课中编写并运行代码吗?
能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 在 React 应用中测量 Core Web Vitals
- 包分析与代码拆分策略
- React 中的图像与字体优化
- 降低 INP:事件处理器优化