当前位置:首页 > 科技  > 软件

React 中,用到的几种浅比较方式及其比较成本科普

来源: 责编: 时间:2024-04-22 09:12:16 108观看
导读开发中的绝大多数时候,我们并不需要关注 React 项目的性能问题。虽然我们在前面几个章节中,也花了几篇文章来分析如何优化 React 的性能体验,但是这些知识点在开发过程中能用到的机会其实比较少。面试的时候用得比较多。

SyN28资讯网——每日最新资讯28at.com

开发中的绝大多数时候,我们并不需要关注 React 项目的性能问题。虽然我们在前面几个章节中,也花了几篇文章来分析如何优化 React 的性能体验,但是这些知识点在开发过程中能用到的机会其实比较少。面试的时候用得比较多。SyN28资讯网——每日最新资讯28at.com

但是,当你的项目遇到性能瓶颈,如何优化性能就变得非常重要。当然,我们前面几篇文章已经把性能优化的方式和方法说得非常清晰了,大家可以回顾一下。这篇文章我们要分享的重点是,当我采用不同的方式优化之后,代码逻辑执行所要付出的代价到底如何。SyN28资讯网——每日最新资讯28at.com

例如,当我们得知 React 的 DIFF 是全量比较的时候,可能第一个反应就是觉得他性能差。但是具体性能差到什么程度呢?有没有一个具体的数据来支撑?不确定,这只是一种主观感受。优化之后的性能到底强不强呢,也不敢肯定。SyN28资讯网——每日最新资讯28at.com

因此,这篇文章主要给大家介绍几种 react 在 diff 过程中用到的比较方式,以及当这几种方式大量执行时,执行所要花费的时间。SyN28资讯网——每日最新资讯28at.com

一、对象直接比较

又称为全等比较,这是一种成本最低的比较方式。在 React 中,state 与 props 的比较都会用到这样的方式。SyN28资讯网——每日最新资讯28at.com

var prevProps = {}var nextProps = {}if (prevProps === nextProps) {  ...}

那么,这种比较方式的成本有多低呢?我们来写一个循环简单验证一下。分别看看比较一万次需要多长时间。SyN28资讯网——每日最新资讯28at.com

var markTime = performance.now()var prev = {}var next = {}for(var i = 0; i <= 10000; i++) {  if (prev === next) {    console.log('相等')  }}var endTime = performance.now()console.log(endTime - markTime)

执行结果会有小范围波动,展示出来的结果都是取的多次执行的平均值,或者出现次数最多的执行结果。比如本案例执行,用时最短的是 0.3 ms,用时最长的是 0.8 ms。SyN28资讯网——每日最新资讯28at.com

可以看到,对比一万次,用时约  0.6ms。SyN28资讯网——每日最新资讯28at.com

SyN28资讯网——每日最新资讯28at.com

对比一百万次,用时约 6.4ms。SyN28资讯网——每日最新资讯28at.com

SyN28资讯网——每日最新资讯28at.com

通常情况下,我们项目的规模应该很难超过一万次,控制得好一点,一般都在 1000 次以内。多一点也应该在 5000 次以内,5000 次用这种方式的对比只需要 0.3ms 左右。SyN28资讯网——每日最新资讯28at.com

二、Object.is

Object.is 是一种与全等比较相似但不同的比较方式,他们的区别就在于处理带符号的 0 和 NaN 时结果不一样。SyN28资讯网——每日最新资讯28at.com

+0 === -0 // trueObject.is(+0, -0) // falseNaN === NaN // falseObject.is(NaN, NaN) // true

React 源码里为 Object.is 做了兼容处理,因此多了一点判断,所以他的性能上会比全等要差一些。SyN28资讯网——每日最新资讯28at.com

function is(x, y) {  return (    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare  );}const objectIs =  typeof Object.is === 'function' ? Object.is : is;

那么差多少呢?我们先写一个逻辑来看一下执行一万次比较需要多久。SyN28资讯网——每日最新资讯28at.com

function is(x, y) {  return (    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare  );}const objectIs =  typeof Object.is === 'function' ? Object.is : is;var markTime = performance.now()var prev = {}var next = {}for(var i = 0; i <= 10000; i++) {  if (objectIs(prev, next)) {    console.log('相等')  }}var endTime = performance.now()console.log(endTime - markTime)

执行结果如下,大概是 0.8ms。SyN28资讯网——每日最新资讯28at.com

SyN28资讯网——每日最新资讯28at.com

执行一百万次,用时约 11.4ms。SyN28资讯网——每日最新资讯28at.com

SyN28资讯网——每日最新资讯28at.com

那么我们的项目规模在 5000 次比较以内的话,用时估计在 0.4ms 左右,比全等比较多用了 0.1ms。SyN28资讯网——每日最新资讯28at.com

三、shallowEqual

这种浅比较的成本就稍微大一些,例如,当我们对子组件使用了 memo 包裹之后,那么在 diff 过程中,对于 props 的比较方式就会转变成这样方式,他们会遍历判断 props 第一层每一项子属性是否相等。SyN28资讯网——每日最新资讯28at.com

function shallowEqual(objA: mixed, objB: mixed): boolean {  if (is(objA, objB)) {    return true;  }  if (    typeof objA !== 'object' ||    objA === null ||    typeof objB !== 'object' ||    objB === null  ) {    return false;  }  const keysA = Object.keys(objA);  const keysB = Object.keys(objB);  if (keysA.length !== keysB.length) {    return false;  }  // Test for A's keys different from B.  for (let i = 0; i < keysA.length; i++) {    const currentKey = keysA[i];    if (      !hasOwnProperty.call(objB, currentKey) ||      !is(objA[currentKey], objB[currentKey])    ) {      return false;    }  }  return true;}

首先,这种比较方式在 React 中出现的次数非常的少,只有我们手动新增了 memo 之后才会进行这种比较,因此,我们测试的时候,先以 1000 次为例看看结果。SyN28资讯网——每日最新资讯28at.com

我们定义两个数量稍微多一点的 props 对象,他们最有最后一项不相同,因此比较的次数会拉满。SyN28资讯网——每日最新资讯28at.com

var prev = {a:1, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1}var next = {a:1, b: 1, c: 1, d: 1, e: 1, f: 1, g: 2}

完整代码如下:SyN28资讯网——每日最新资讯28at.com

function is(x, y) {  return (    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare  );}const objectIs =  typeof Object.is === 'function' ? Object.is : is;function shallowEqual(objA, objB) {  if (is(objA, objB)) {    return true;  }  if (    typeof objA !== 'object' ||    objA === null ||    typeof objB !== 'object' ||    objB === null  ) {    return false;  }  const keysA = Object.keys(objA);  const keysB = Object.keys(objB);  if (keysA.length !== keysB.length) {    return false;  }  // Test for A's keys different from B.  for (let i = 0; i < keysA.length; i++) {    const currentKey = keysA[i];    if (      !Object.hasOwnProperty.call(objB, currentKey) ||      !is(objA[currentKey], objB[currentKey])    ) {      return false;    }  }  return true;}var markTime = performance.now()var prev = {a:1, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1}var next = {a:1, b: 1, c: 1, d: 1, e: 1, f: 1, g: 2}for(var i = 0; i <= 1000; i++) {  if (shallowEqual(prev, next)) {    console.log('相等')  }}var endTime = performance.now()console.log(endTime - markTime)

1000 次比较结果耗时如下,约为 1.4ms。SyN28资讯网——每日最新资讯28at.com

SyN28资讯网——每日最新资讯28at.com

5000 次比较结果耗时如下,约为 3.6ms。SyN28资讯网——每日最新资讯28at.com

SyN28资讯网——每日最新资讯28at.com

10000 次比较结果耗时如下,约为 6.6 ms。SyN28资讯网——每日最新资讯28at.com

SyN28资讯网——每日最新资讯28at.com

这里我们可以做一个简单的调整,让对比耗时直接少一半。那就是把唯一的变化量,写到前面来,如图所示,耗时只用了 3.1ms。SyN28资讯网——每日最新资讯28at.com

SyN28资讯网——每日最新资讯28at.com

运用到实践中,就是把 props 中的变量属性,尽量写在前面,能够大幅度提高对比性能。SyN28资讯网——每日最新资讯28at.com

四、总结

次数
SyN28资讯网——每日最新资讯28at.com

全等
SyN28资讯网——每日最新资讯28at.com

is
SyN28资讯网——每日最新资讯28at.com

shallow
SyN28资讯网——每日最新资讯28at.com

五千
SyN28资讯网——每日最新资讯28at.com

0.3
SyN28资讯网——每日最新资讯28at.com

0.4
SyN28资讯网——每日最新资讯28at.com

3.6
SyN28资讯网——每日最新资讯28at.com

一万
SyN28资讯网——每日最新资讯28at.com

0.6
SyN28资讯网——每日最新资讯28at.com

0.8
SyN28资讯网——每日最新资讯28at.com

6.6
SyN28资讯网——每日最新资讯28at.com

百万
SyN28资讯网——每日最新资讯28at.com

6.4
SyN28资讯网——每日最新资讯28at.com

11.4
SyN28资讯网——每日最新资讯28at.com

162
SyN28资讯网——每日最新资讯28at.com

因此我们从测试结果中看到,全量 diff 并不可怕,如果你对性能优化的理解非常到位,那么能你的项目中,全量 diff 所花费的时间只有 0.几ms,理论的极限性能就是只在你更新的组件里对比出差异,执行 re-render。SyN28资讯网——每日最新资讯28at.com

当然,由于对于 React 内部机制的理解程度不同,会导致一些差异,例如有些同学的项目中,会执行过多的冗余 re-render。从而导致在大型项目中性能体验可能出现问题。那么这种情况下,也不用担心,有一种超级笨办法,那就是在项目中,结合我们刚才在 shallowEqual 中提高的优化方案,无脑使用 useCallback 与 memo,你的项目性能就能得到明显的提高,当然,这个方案不够优雅但是管用。SyN28资讯网——每日最新资讯28at.com

可以看出,React 性能优化最重要的手段非常简单:就是控制当前渲染内容的节点规模。SyN28资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-84462-0.htmlReact 中,用到的几种浅比较方式及其比较成本科普

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 利用RSA加密打造强大License验证,确保软件正版合法运行

下一篇: 针对尺寸单位,为什么不应该使用 px 作为尺寸单位?以及最佳实践!

标签:
  • 热门焦点
Top
Baidu
map