大家好,我卡颂。
对于长期迭代的 React
我的项目,性能是不能漠视的问题。通常咱们通过:
React-Dev-Tools
的Profiler
面板- 一些第三方工具,比方 why-did-you-render
检测运行时性能瓶颈。
实际上,React
自身就内置了性能检测组件 —— Profiler
,能够很不便的检测 React
我的项目的性能。
欢送退出人类高质量前端交换群,带飞
应用形式
Profiler
是个内置组件,用他包裹须要检测性能的组件即可:
<Profiler id="App" onRender={onRender}>
<App />
</Profiler>
嵌套应用也是能够的:
<App>
<Profiler id="Sidebar" onRender={onRender}>
<Sidebar />
</Profiler>
<Profiler id="Content" onRender={onRender}>
<Content />
</Profiler>
</App>
Profiler
会检测被他包裹的组件树的性能,检测后果会作为 onRender
回调的参数:
function onRender(
id,
phase,
actualDuration, baseDuration,
startTime, commitTime
) {// ... 回调}
那么,这些参数都是什么意思呢?其实咱们齐全没必要记这些。
咱们只须要晓得,一些典型的性能优化场景该应用哪些参数就行。
场景 1:组件是不是嵌套更新?
对于个别的组件更新,会经验 4 个步骤:
- 组件触发更新
- 计算更新的影响
- 执行
DOM
操作 - 视图更新
但如果在上一次更新流程的 4 个步骤还未走完的状况下,又触发新的更新:
能够发现,在这种状况下,视图更新 的机会远滞后于个别更新流程,这会造成页面交互卡顿。
这就是 组件嵌套更新 ,通常咱们在useLayoutEffect
中触发新的更新会遇到这种状况。
Profiler
onRender
回调的 phase
参数,用来示意组件所处更新阶段:
mount
,代表组件是首屏渲染update
,代表组件更新nested-update
,代表组件嵌套更新
通过该参数能够判断组件是否处于嵌套更新。
当遇到嵌套更新造成的性能问题,能够思考用 useEffect
代替useLayoutEffect
。
场景 2:性能优化到底起没起作用?
当提到 性能优化,很多同学第一反馈就是:
useCallback
useMemo
React.memo
但当咱们应用这些性能优化 API
后,咱们怎么晓得性能是否变得更好?
为了检测优化成果,通常会在要害组件打印个 log
,如果状态更新后log
没打印,代表组件没有render
,命中缓存胜利,比方这样:
function App() {console.log('App render')
// ... 省略逻辑
}
但这样并不能反映性能优化的整体成果。这时候能够思考 Profiler
中的 actualDuration
与baseDuration
参数:
baseDuration
掂量组件子树在不命中任何缓存时,残缺render
一次所花工夫actualDuration
掂量组件子树理论残缺render
一次所花工夫
所以,用 baseDuration
减去 actualDuration
残余的工夫,就是性能优化节约的工夫。
比方,对上面的 <App/>
组件性能优化后,只须要在 onRender
中比拟 baseDuration
与actualDuration
之间的差就能度量 <App />
的性能优化成果:
<Profiler id="App" onRender={onRender}>
<App />
</Profiler>
这个值越高,代表性能优化成果越好。当靠近 0 时,代表性能优化没有起到作用。
须要留神的是,
baseDuration
是通过子树中每个组件最近render
所需工夫汇总求和失去的近似值,有时并不精确
如果你的共事执著的认为所有函数 props
都必须用 useCallback
包裹,所有变量 props
都必须用 useMemo
包裹,请用以上数据狠狠的和他讲道理。
场景 3:我的项目的性能瓶颈在哪?
当咱们要做性能优化时,首先应该明确 —— 我的项目的性能瓶颈在哪?此时,能够用 Profiler
划分几个 待比拟区域,再别离比照actualDuration
。
比方,对于上面的利用:
<App>
<Sidebar />
<Content />
</App>
<Sidebar />
和 <Content />
谁render
更耗时?
此时能够用 Profiler
别离包裹这两个组件:
<App>
<Profiler id="Sidebar" onRender={onRender}>
<Sidebar />
</Profiler>
<Profiler id="Content" onRender={onRender}>
<Content />
</Profiler>
</App>
再别离在 onRender
中掂量 actualDuration
,值比拟高的区域render
更耗时。
这种形式定制性比拟高。如果想更直观比拟哪些组件 render
更耗时,能够应用 React Dev Tools
中Profiler
面板的火炬图。
总结
Profiler
是 React
内置的性能剖析组件,用于度量其包裹的子树的渲染性能。
最初说个有意思的细节 —— 在官网 Profiler 局部中只介绍了 Profiler
有onRender
这个回调。
从 Profiler
源码看,他还存在:
onCommit
回调onPostCommit
回调onNestedUpdateScheduled
回调
不晓得为什么,他们没有在文档中提及。