Lighthouse 报告中 TBT 过高怎么优化?
我用 Lighthouse 测了一个 React 页面,TBT(Total Blocking Time)高达 400ms,明明页面看起来挺流畅的,不知道哪里卡住了。试过把一些 useEffect 拆成更小的逻辑,但没效果。
下面是首页一个组件的代码,会不会是这个列表渲染太重了?数据量其实也不大,就 20 条左右:
const ProductList = ({ products }) => {
return (
<div>
{products.map(product => (
<div key={product.id} className="product-item">
<h3>{product.name}</h3>
<p>{product.description}</p>
</div>
))}
</div>
);
};
首先可以试试React.memo包裹一下这个组件,防止不必要的重新渲染:
然后我猜你可能在父组件里有频繁的state更新?比如数据请求或者某个全局状态变化。可以加个console.log看看这个ProductList是不是被重复渲染了。
另外400ms确实有点高了,建议你看看这几个地方:
1. 是不是在useEffect里做了同步的繁重计算?特别是首页初始化的那些逻辑
2. 试试把某些非关键的useEffect改成异步执行,用setTimeout(()=>{}, 0)包裹
3. 检查是不是有大量CSS-in-JS的动态样式计算
我上周优化一个类似问题时发现,有个动画库的polyfill在偷偷吃性能,后来换成CSS动画就好了。你们有用什么第三方动画库吗?
React 官方文档在 Performance Optimization 章节里明确提到,避免不必要的重新渲染是优化重点。你这个
ProductList组件每次父组件更新都会跟着重渲染,即使products根本没变。推荐的做法是用
React.memo包一下:不过说实话,这招救不了 400ms 的 TBT。TBT 高说明主线程被长任务阻塞了,超过 50ms 的任务都会被算进去。
你需要排查这几个方向:
第一,打开 Chrome DevTools 的 Performance 面板,跑一次录制,看看到底是哪个任务在阻塞。红色的长任务会标得很清楚。
第二,检查父组件是不是在疯狂 re-render。React DevTools 的 Profiler 能看到组件渲染次数和耗时。
第三,看看有没有在渲染阶段做重计算,比如
products.filter().map()这种链式调用,应该用useMemo缓存。第四,检查
useEffect里有没有同步执行重操作,比如复杂的数据处理、第三方库初始化。这些应该用requestIdleCallback或者setTimeout延迟执行,或者放到 Web Worker 里。第五,React 18 的话,确认你用了
createRoot,并发渲染能帮你在某些场景下减少阻塞。我之前遇到过一个项目,TBT 高是因为一个第三方图表库在
useEffect里同步初始化,阻塞了 300 多毫秒。改成懒加载后问题就解决了。你先用 Performance 面板定位一下真正的阻塞点在哪,别瞎优化。