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

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

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

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

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

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

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

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

一、对象直接比较

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

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

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

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

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

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

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

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

二、Object.is

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

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

React 源码里为 Object.is 做了兼容处理,因此多了一点判断,所以他的性能上会比全等要差一些。PAh28资讯网——每日最新资讯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;

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

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

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

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

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

三、shallowEqual

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

我们定义两个数量稍微多一点的 props 对象,他们最有最后一项不相同,因此比较的次数会拉满。PAh28资讯网——每日最新资讯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}

完整代码如下:PAh28资讯网——每日最新资讯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。PAh28资讯网——每日最新资讯28at.com

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

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

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

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

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

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

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

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

四、总结

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

标签:
  • 热门焦点
  • 卢伟冰长文解析K60至尊版 对Redmi有着里程碑式的意义

    在今天的Redmi后性能时代战略发布会结束之后,Redmi总经理卢伟冰又带来了一篇长文,详解了为什么 Redmi 要开启后性能时代?为什么选择和 MediaTek、Pixelworks 深度合作?以及后性
  • 红魔电竞平板评测:大屏幕硬实力

    前言:三年的疫情因为要上网课的原因激活了平板市场,如今网课的时代已经过去,大家的生活都恢复到了正轨,这也就意味着,真正考验平板电脑生存的环境来了。也就是面对着这种残酷的
  • 8月总票房已突破10亿!《封神》第一:口碑已经成了

    8月5日消息,据灯塔专业版数据,截至8月5日9时35分,8月总票房(含预售)已突破10亿。其中,《封神》以大比分的优势领先。根据官方消息,目前该片总票房已经超过14.
  • Raft算法:保障分布式系统共识的稳健之道

    1. 什么是Raft算法?Raft 是英文”Reliable、Replicated、Redundant、And Fault-Tolerant”(“可靠、可复制、可冗余、可容错”)的首字母缩写。Raft算法是一种用于在分布式系统
  • K8S | Service服务发现

    一、背景在微服务架构中,这里以开发环境「Dev」为基础来描述,在K8S集群中通常会开放:路由网关、注册中心、配置中心等相关服务,可以被集群外部访问;图片对于测试「Tes」环境或者
  • 认真聊聊东方甄选:如何告别低垂的果实

    来源:山核桃作者:财经无忌爆火一年后,俞敏洪和他的东方甄选依旧是颇受外界关心的&ldquo;网红&rdquo;。7月5日至9日,为期5天的东方甄选&ldquo;甘肃行&rdquo;首次在自有App内直播,
  • 半导体需求下滑 三星电子DS业务部门今年营业亏损预计超10万亿韩元

    7月17日消息,据外媒报道,去年下半年开始的半导体需求下滑,影响到了三星电子、SK海力士、英特尔等诸多厂商,营收明显下滑,部分厂商甚至出现了亏损。作为
  • iQOO 11S新品发布会

    iQOO将在7月4日19:00举行新品发布会,推出杭州亚运会电竞赛事官方用机iQOO 11S。
  • 北京:科技教育体验基地开始登记

      北京“科技馆之城”科技教育体验基地登记和认证工作日前启动。首批北京科技教育体验基地拟于2023年全国科普日期间挂牌,后续还将开展常态化登记。  北京科技教育体验基
Top