0Pricing
React Academy · 课时

降低 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 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 使用合成事件委托(将一个监听器附加到根元素)。避免在 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 在 React 应用中测量 Core Web Vitals
  2. 包分析与代码拆分策略
  3. React 中的图像与字体优化
  4. 降低 INP:事件处理器优化
← 返回 React Academy