提高React界面性能的十个小技巧

更新日期: 2021-05-12阅读: 1.5k标签: 性能

众所周知,没有人会喜欢响应缓慢的Web界面。而作为最受欢迎的JavaScript框架之一,react提供了多种提高UI性能的方法。下面让我们一探究竟吧。

总的说来,React是通过维护视图中的内存(in-memory)模型来运作的。这通常被称为虚拟dom,它可以被用来确定实际DOM何时需要被更新。不过,由于操控实际DOM的成本较高,因此我们需要确保仅在必要时才去更新DOM,进而提高整体性能。

为了从React框架中获取最高性能,并提升React界面的响应效率,本文将从各种功能函数(如Suspense)、以及基于类的组件出发,和您讨论十项常用的、面向DOM的技术与方法。


shouldComponentUpdate

在编写基于类的组件时,您可以重写shouldComponentUpdate()的生命周期方法。该方法的目的在于:明确地声明目标组件是否需要被重新渲染(re-rendering)。值得注意的是,在更新实际DOM的生命周期中,渲染的开销是非常巨大的。因此,只有在组件的属性(props)或状态(states)发生变化时,我们才需要让React执行渲染。有时您甚至可以跳过渲染,以避免整体调用所产生的开销。

shouldComponentUpdate的签名和操作比较简单。在如下简单示例中,组件需要知晓应该在何种指定触发条件下,去执行更新。该方法将接收到的属性与状态当作参数,如果返回为true,组件将执行渲染,否则并不触发渲染。

shouldComponentUpdate(nextProps, nextState) { 
    if (this.props.significant !== nextProps.significant) { 
      return true; 
    } 
    return false; 
  } 

虽然上述代码段主要检查的是属性,但是它对于状态也同样适用。当然,在实际应用中,对于属性或状态的检查,并判定是否返回true,可能会更加复杂。如果您需要比较某个简单的浅层值(shallow value),那么请使用下一个技巧--PureComponent。


PureComponent

如果您的组件仅需要对属性和状态进行简单的浅层比较(shallow comparison,https://stackoverflow.com/a/5703797/467240),以确定是否需要渲染,那么完全可以使用PureComponent之类的扩展基类--class MyComponent extends React.PureComponent。它可以实现:当通过浅层比较,并未发现属性或状态发生了任何变化时,render()就不会被调用。顾名思义,PureComponent表示:仅在属性或状态改变时,才会触发输出的更改,因此该组件是纯净的,不会带有任何副作用。


useEffect

前面的技巧仅适用于那些基于类的组件。为了达到与常规功能性组件相似的效果,您可以使用useEffect hook和memo之类的功能性组件。其中,useEffect与shouldComponentUpdate有着相似的效果,它允许用户指定:仅在某些变量发生更改的情况下,生效某种特定的功能 ,从而避免了整体变更的开销。下面是一个简单的useEffect示例:

const MyComponent = (props) => { 
  useEffect(() => { 
    console.info("Update Complete: " + props.significantVariable); 
  }, [props.significantVariable]); 
} 

由上述代码段可知,如果props.significantVariable已被更改(即变量发生了变化),那么该代码就会运行生效。


用React.memo提供记忆

作为一个高阶组件,memo包装了各种组件,并扩展了它们的行为能力。也就是说,如果功能性组件具有相同的属性,memo便能够以缓冲的方式,“记住”它们的结果。据此,它可以有效地防止功能性组件在无视属性是否一致的情况下,去盲目地执行渲染。

为了模仿PureComponent只关注属性的行为,我们可以使用如下代码段来包装某些功能性组件,使其只检查属性的更改,而非状态。由于属性和状态是不同的,因此通过比较,一旦props.quote被认定为未发生改变,则其对应的组件也不会重新渲染。

const MyComponent = (props) => { 
  return <span>props.quote</span> 
} 
export default React.memo(SomeComponent) 

同时,React.memo 可以通过第二个参数,来检查函数的等效性:

export default React.memo(MyComponent, (oldProps, newProps) => {} ); 

通过上述代码,我们可以实现对用例新的和旧的属性进行比较。如果属性相等,该函数则返回true。值得注意的是,这与我们在前面介绍的shouldComponentUpdate,在发现组件出现更新时返回true,正好相反。


窗口化(列表虚拟化)

现在,让我们将注意力转移到一项同时适用于功能性和类组件的技术--窗口化(windowing)上。例如有一个具有数千行记录的数据表或列表,如果您想在该表所对应的应用界面上显示大量数据集,那么就需要采用“窗口化”的方式来查询数据。也就是说,我们可以通过一次性仅加载和显示部分数据的形式,防止大量数据“卡死”应用的用户界面(UI)。为此,我们时常可以用到react-window库(请参见--https://github.com/bvaughn/react-window)。


函数缓存

如果您觉得函数调用的成本过高,那么可以考虑对其进行缓存。如果各个参数相同,而且缓存能够返回结果,我们就可以使用存储式缓存(memorized cache)的方式,来避免各种针对数据获取的调用。当然,函数缓存是否真的适用,还取决于函数的具体特征。


延迟加载和代码拆分

所谓延迟加载是指:我们仅在必要时,才去加载数据。React 16.6引入了React.lazy(),它允许用户对代码按需进行拆分。这意味着,您可以在使用常规组件语法的同时,获得各种延迟加载的语义。

当然,React 16.6之前的版本,并非无法实现代码拆分,只是在处置大型代码库时,相对比较繁琐。


并发模式、Suspense和useDeferredValue

作为React 16的一项最显著的新功能, 并发模式 可以让用户通过使用Suspense组件,实现数据获取和渲染的并行处理,进而极大地提高应用程序的实际感知性能。

我们除了能够用Suspense组件来定义数据的获取区域之外,还可以使用诸如useDeferredValue等由React 16带来的新组件,来提升自动建议(auto-suggest)等工作方式,进而避免用户碰到诸如错误性的键入等不良的体验。


数据获取的防抖(Debounce)和限流(throttle)

大多数情况下,我们可以通过debounce或throttle函数,来更好地处理React的并发模式。如果您的代码库被锁定为旧版的渲染引擎,而无法开启并发模式时,此类函数便可以有效地避免在数据获取的过程中,出现混乱的局面。

例如,如果您想在用户键入数据的同时,实时地获取他们的输入,那么由于每个击键都会触发一个请求,因此整体的性能会大打折扣。对此,我们便可以使用debounce或throttle函数,来缓解此类问题。


分析(Profiling)

除了上面提到的技术,我们还可以通过对应用程序进行性能分析,来获悉性能瓶颈的所在,并验证上述改进方法的实际效果。目前,像Chrome和Firefox之类的浏览器,都带有内置的分析器(profiler)。一旦启用了React的开发模式(dev mode),您将可以通过分析器,来查看某些正在使用的特定组件。这对于检查网络的状态,以及识别后端调用的延迟,都是非常实用的。据此,您可以清晰地判断出,到底是前端JavaScript的代码问题,还是存在着需要后端修复的缺陷。

此外,React 16.5以及更高的版本,还提供了一个名为DevTools Profiler(https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html)的工具。它既能够为处于并发模式的各个函数,提供了更加详尽的服务功能与集成;又可以通过多种方法,对应用程序的行为活动进行切片(slice)和切块(dice)。

另一类 Profiler组件 则能够展现组件渲染生命周期中的各种详细信息。


React的生产环境构建

最后,在部署生产环境时,您还需要确保生产环境构建(production build)的精简性、且不包含任何开发调试过程中的日志记录。当然,具体步骤取决于您所使用的构建工具。如果您使用的是Create React App,则请参考--https://create-react-app.dev/docs/production-build/。

原文标题:10 tips for tuning React UI performance,作者:Matthew Tyson
来自:http://developer.51cto.com/art/202105/661918.htm


链接: https://fly63.com/article/detial/10281

提高js加载速度,实现js无阻塞加载方式,高性能的加载执行JavaScript

为解决JS加载速度慢,采用js的延时加载,和动态加载。由于js的堵塞特性,当浏览器在加载javascript代码时,不能同时做其他任何事情,如果javascript执行时间越久,浏览器等待响应的时间就越久。

如何提高CSS性能?CSS优化、提高性能提升总汇

如何提高CSS性能,根据页面的加载性能和CSS代码性能,主要表现为: 加载性能 (主要是从减少文件体积,减少阻塞加载,提高并发方面入手),选择器性能,渲染性能,可维护性。

前端性能优化_css加载会造成哪些阻塞现象?

css的加载是不会阻塞DOM的解析,但是会阻塞DOM的渲染,会阻塞link后面js语句的执行。这是由于浏览器为了防止html页面的重复渲染而降低性能,所以浏览器只会在加载的时候去解析dom树,然后等在css加载完成之后才进行dom的渲染以及执行后面的js语句。

2018 前端性能检查表

性能十分重要。然而,我们真的知道性能瓶颈具体在哪儿吗?是执行复杂的 JavaScript,下载缓慢的 Web 字体,巨大的图片,还是卡顿的渲染?研究摇树(Tree Shaking),作用域提升(Scope Hoisting)

高性能Javascript总结

Js高性能总结:加载和运行、数据访问、DOM编程、算法和流程控制、响应接口、Ajax 异步JavaScript和XML、编程实践...

优化网站性能规则_前端性能优化策略【网络加载、页面渲染】

前端网站性能优化规则:网络加载类、页面渲染类。包括:减少 HTTP 资源请求次数、减小 HTTP 请求大小、避免页面中空的 href 和 src、合理设置 Etag 和 Last-Modified、使用可缓存的 AJAX、减少 DOM 元素数量和深度等

前端性能的本质是什么?

性能一直以来是前端开发中非常重要的话题。随着前端能做的事情越来越多,浏览器能力被无限放大和利用:从 web 游戏到复杂单页面应用,从 NodeJS 服务到 web VR/AR 和数据可视化,前端工程师总是在突破极限

BigPipe_高性能流水线页面技术

BigPipe是一个重新设计的基础动态网页服务体系。大体思路是,分解网页成叫做Pagelets的小块,然后通过Web服务器和浏览器建立管道并管理他们在不同阶段的运行。这是类似于大多数现代微处理器的流水线执行过程:多重指令管线通过不同的处理器执行单元,以达到性能的最佳。

用CSS开启硬件加速来提高网站性能

你知道我们可以在浏览器中用css开启硬件加速,使GPU (Graphics Processing Unit) 发挥功能,从而提升性能吗?现在大多数电脑的显卡都支持硬件加速。鉴于此,我们可以发挥GPU的力量,从而使我们的网站或应用表现的更为流畅。

原生js实现懒加载并节流

像淘宝网站等,页面中有着大量图片,一次性全部加载这些图片会使浏览器发送大量请求和造成浪费。采用懒加载技术,即用户浏览到哪儿,就加载该处的图片。这样节省网络资源、提升用户体验、减少服务器压力。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!