我们的一些开发人员最近提出了一个问题,什么时候我应该在 React 中使用 usemo?这是一个非常好的问题。在本文中,我们将使用一种科学的方法,定义一个假设,并在 React 中使用现实生活中的基准对其进行测试。
请继续阅读,了解 useMomo 对性能的影响。
什么是 useMomo?
useMomo 是 React 提供的一个hook 函数。这个钩子允许开发人员缓存变量的值和依赖列表。如果此依赖项列表中的任何变量发生更改,React 将重新运行此数据的处理并重新缓存它。如果依赖项列表中的变量值之前已经缓存过,则 React 将从缓存中获取值。
这主要是对组件的重新呈现有影响。一旦组件重新呈现,它将从缓存中提取值,而不必一次又一次地循环数组或处理数据。
react 官方是怎么介绍useMenu的?
我们咋一看一下 的 React 文档,关于 usemo,它在应该使用它的时候并没有被提及。他们只是简单地提到它的作用和使用方法。
这里的探讨关于 useMomo 的使用问题是是有趣的!
在我们看到使用 useMomo 的性能优势之前,数据应该有多复杂或大?开发者应该什么时候使用 usemo?
实验
在我们开始实验之前,让我们先定义一个假设。
让我们首先定义要执行的对象和处理的复杂性为 n。如果 n = 100,那么我们需要循环遍历一个由100个条目组成的数组,以获得 memo-ed 变量的最终值。
然后,我们还需要将两个操作分开。第一个动作是组件的初始呈现。在这种情况下,如果一个变量使用 useMomo 或不使用 usemo,它们都必须计算初始值。一旦完成了第一次渲染,随后用 useMomo 重新渲染(我们需要测量的第二个操作) ,可以从缓存中检索值,其中的性能优势应该与非备注版本相比可见。
在所有情况下,为了建立备忘缓存并存储值,我预计在初始呈现期间会有大约5-10% 的开销。当 n < 1000时,我期望看到 useMomo 的性能下降。对于 n > 1000,我希望看到类似或更好的性能与 useMomo 重新渲染,但初始渲染应该仍然略慢,由于额外的缓存算法。你的猜测是什么?
基准测试设置
我们设置了一个小的 React 组件如下,它将生成一个复杂度为 n 的对象,复杂度定义在props level 。
- BenchmarkNormal.jsx
import React from 'react';
const BenchmarkNormal = ({level}) => {
const complexObject = {
values: []
};
for (let i = 0; i <= level; i++) {
complexObject.values.push({ 'mytest' });
}
return ( <div>Benchmark level: {level}</div>);
};
export default BenchmarkNormal;
这是我们正常的基准组件,我们还将为 useMomo 做一个基准组件 BenchmarkMemo。
- BenchmarkMemo.jsx
import React, {useMemo} from 'react';
const BenchmarkMemo = ({level}) => {
const complexObject = useMemo(() => {
const result = {
values: []
};
for (let i = 0; i <= level; i++) {
result.values.push({'mytest'});
};
return result;
}, [level]);
return (<div>Benchmark with memo level: {level}</div>);
};
export default BenchmarkMemo;
然后,我们在 App.js 中设置这些组件,以便在按下按钮时显示。我们还使用 React 的 来提供渲染时间
function App() {
const [showBenchmarkNormal, setShowBenchmarkNormal] = useState(false);
// Choose how many times this component needs to be rendered
// We will then calculate the average render time for all of these renders
const timesToRender = 10000;
// Callback for our profiler
const renderProfiler = (type) => {
return (...args) => {
// Keep our render time in an array
// Later on, calculate the average time
// store args[3] which is the render time ...
};
};
// Render our component
return <p> {showBenchmarkNormal && [...Array(timesToRender)].map((index) => {
return <Profiler id={`normal-${index}`} onRender={renderProfiler('normal')}>
<BenchmarkNormal level={1} />
</Profiler>;
})}
</p>;
}
如您所见,我们渲染组件10000次,并获取这些组件的平均渲染时间。现在我们需要一种机制来触发组件的按需重新呈现,同时不必重新计算 usemo,因此我们不希望修改 useMemo 的依赖列表中的任何值。
重新渲染触发机制
为了保持结果的清晰,我们总是在开始测试之前从一个新的浏览器页面开始(除了重新渲染) ,以清除任何可能仍然在页面上并影响我们的结果的缓存。
结果
复杂度 n = 1的结果
复杂度在左列显示,第一个测试是初始渲染,第二个测试是第一次重新渲染,最后一个测试是第二次重新渲染。第二列显示了普通基准测试的结果,不包括 useMomo。最后一列显示了使用 useMomo 的基准测试的结果。这些值是我们的基准组件渲染时间超过10000次的平均值。
当使用 useMomo 时,初始渲染会慢19% ,这比预期的5-10% 要高得多。随后的渲染仍然很慢,因为通过 useMomo 缓存的开销比重新计算实际值的开销更大。
总之,对于复杂度 n = 1,不使用 useMomo 总是更快,因为开销总是比性能增益更昂贵。
复杂度 n = 100的结果
在复杂度为100的情况下,使用 useMomo 的初始渲染变慢了62% ,这是一个相当大的数量。后续的重新投票似乎平均要稍微快一点或者差不多。
总之,复杂度为100的初始渲染显著地慢,而随后的重新渲染相当类似,最多只是稍微快一点。在这一点上,useMomo 似乎还没有什么意思。
复杂度 n = 1000的结果
由于复杂度为1000,我们注意到使用 useMomo 的初始渲染变慢了183% ,因此可以推测,useMomo 缓存更难存储这些值。后续渲染大约快37% !
在这一点上,我们可以看到一些性能提高在重新呈现,但它不是没有成本来。最初的渲染速度要慢得多,损失了183% 的时间。
总之,在复杂度为1000的情况下,我们可以看到在初始渲染时性能损失更大(183%) ,然而,随后的渲染速度要快37% 。
这是否已经很有用将在很大程度上取决于您的用例。一个183% 的性能损失在初始渲染是一个艰难的销售,但可能是合理的情况下,很多重新呈现的组件。
复杂度 n = 5000的结果
在复杂度为5000的情况下,我们注意到 useMomo 的初始渲染速度要慢545% 。看起来数据和处理的复杂度越高,初始渲染的速度就越慢。
有趣的部分来自于再次的渲染。在这里,我们注意到在每个后续渲染中 useMomo 的性能提高了437% 到609% 。
总之,使用 useMomo 的初始渲染更加昂贵,但是随后的重新渲染会有更大的性能提升。如果您的应用程序的数据/处理复杂度大于5000并且有一些重新渲染,我们可以看到使用 useMomo 的好处。
结果说明
友好的读者社区已经指出了一些可能的原因,比如为什么初始渲染会慢很多,比如运行生产模式等等。我们重新测试了所有的实验,发现结果是相似的。这些比率相似,但实际值可能更低。所有的结论都是一样的。
总结
这些是组件的复杂度为 n 的结果,其中应用程序将循环并向数组中添加值 n 次。请注意,结果将根据您处理数据的具体方式以及数据量而有所不同。但是,这应该能够让您了解不同大小的数据集的性能差异。
是否应该使用 useMemo 将在很大程度上取决于您的用例,但是由于复杂度小于100,useMemo 似乎没什么意思。
值得注意的是,useMemo 最初的渲染在性能方面遭受了相当大的挫折。我们预计初始性能损失大约为5-10% ,但发现这在很大程度上取决于数据/处理的复杂性,甚至可能导致500% 的性能损失,这比预期的性能损失多100倍。
我们已经重新运行了几次测试,甚至在得到结果之后,我们可以说后续的结果是非常一致的,类似于我们已经记录下来的最初结果。
关键点
我们都同意,通过保持变量的相同对象引用,useMemo 可以有效地避免不必要的重复渲染。
对于使用 useMemo 缓存实际计算的情况,其主要目标不是避免在子组件中重新渲染:
- 当处理量很大时,应该使用 useMemo
- 从什么时候 useMemo 变得有用以避免额外处理,阈值在很大程度上取决于您的应用程序
- 数据在处理非常低的情况下使用 useMemo,可能会有额外的使用开销
你什么时候使用 useMemo? 这些发现会改变你何时使用 useMemo 的想法吗?请在评论中告诉我们!
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!