翻译原文链接:https://blog.vixlet.com/react-at-light-speed-78cd172a6411

个人翻译小站链接:http://www.zcfy.cc/article/react-at-light-speed-vixlet-2920.html

在过去的几年里, 我们Vixlet (http://www.vixlet.com) 的web团队,着手了一项激动人心的项目,将我们的整个web应用迁往React+Redux的建设。对于我们整个团队来说

这是一个不断增长的机会,而且在这个项目过程中,我们一直充满着挑战。

自此我们的web-app中,包含有几百甚至上千的媒体,文本,视频以及链接等内容,我们花了很长的时间去摸索关于react构建的方式,这里我们将分享一些踩过的经验。

声明: 讲解的这些经验和方法,已经能够很好的满足我们特殊应用的需求,然而,如果是整体开发的话,将你的应用和团队考虑其中至关重要,React的速度是相当快的,所以你可能没有必要很精确的了解到我们的使用场景,但是,我们希望你能发现一些发送的有益的信息。

基本原理

向更大的世界迈出一步.

The render() 函数

作为一个通用原则,尽量在render函数里面少做事,如果实在很有必要运行一些复杂的操作和计算,也许可以考虑将他们移到 memoized 函数里面, 这样得到的结果能够被缓存.了解 Lodash.memoize 关于 memoization函数的模型.

相反地,去避免更改巨大的,轻易计算的值在组件中的状态是很重要的。例如,如果props参数同时包含 firstName 和 lastName,那么就没必要在state状态里面包含 fullName ,因为它很容易从props属性里面获得。 如果一个值能以一种很有效的方式通过props获得,通过使用通用的字符串连接,或者基本的的算法操作,那么我们就没必要更改状态来获取该值了。

Prop 和 Reconciliation

这是很重要的,记住React触发时,是会重新渲染的,其prop值(或者state状态)跟之前的值是不相等的。它包含了在嵌套组件,且其props和state包含对象或者数组之内的任何变化,记住这一点,这是很重要的情况,就是可能不经意的render循环,去创造prop或者state的值,就可能引起巨大的性能冲击。

例如: 函数绑定问题

例如: 对象或者数组的字面值

例如_: 注意fallback返回的值

尽可能的保证Props(和state)最小

一般来讲,props是在被需要的情况下,才会传递给一个组件,通过一个大且复杂的对象,或者很多个单独的props传递给组件,仅仅只是为了给其子组件传递值,但这会引起不必要的组件渲染(同时增加了开发的复杂性).

在我们Vixlet这边,我们使用Redux作为state的容器,因此在我们的这种情况,大部分是从react-redux中使用connect()函数,根据组件中的每一个等级去直接获取需要的数据。connect()函数是非常高性能并且占用的开销非常小。

组件方法

自从给每一个组件实列赋予了组件的方法,如果可以的,你要么使用纯粹的来自helper/util模板中的函数,要么使用静态类方法,这里有一个特别值得注意的地方,就是当有很大数字的组件在app里面进行渲染的时候。

高级

读完我的观点,jank变得邪恶了!

shouldComponentUpdate()

React生命周期中包含一个的方法 [shouldComponentUpdate()](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate).这个方法可以告诉React,组件是否应该被渲染或者不依赖当前或者下一个props/state的值。

然而使用这个方法有个问题,那就是开发者必须仔细考虑每一种重新渲染发生的条件。这就使逻辑变得很复杂,通常来说,这太痛苦了,如果你真的需要它,那你就使用 shouldComponentUpdate()方法,但是对于很多的情况,一般都有更好的选择。

React.PureComponent

React v15版本开始,其包含了 PureComponent类,可以用来建立组件。React.PureComponent基本实现了它自己的shouldComponentUpdate()方法,并且能够自动判断出当前以及下一个props/state组件之间的比较。如果想看更多的信息,请至Stack Overflow:

http://stackoverflow.com/questions/36084515/how-does-shallow-compare-work-in-react

在几乎所有的情况中,React.PureComponent无疑是比React.Component更好的选择.当创建一个新的组件时候,试着将其建立为一个纯粹的组件先,并且将组件功能引入,使用React.Component.

更多信息: [React.PureComponent](https://facebook.github.io/react/docs/react-api.html#react.purecomponent)官方React文档

组件运行分析 (in Chrome)

在最新Chrome版本,新增了一个建立时间表功能的工具,它可以将React组件渲染详细的信息,以及所花的时间显示出来。使用该功能只需要添加?react_perf放在你想测试的url的后面即可。React渲染的时间列表数据,将会在用户时间部分之下显示。

更多信息: Profiling Components with Chrome Timeline官方React文档

有用的Utility: why-did-you-update

这是一个很好的NPM包,当没有必要重新渲染组件的时候,它能进行补丁,在console里面打印出来通知。

注: 这个模块能够使用过滤器进行初始化,去匹配特殊的你想要的组件,否则你的所有console出来的东西,都会被识别为垃圾信息,或者你的浏览器可能会崩溃,至 why-did-you-update docs获取更多细节信息。

常见的性能陷阱

setTimeout() and setInterval()

使用 setTimeout() or setInterval()在一个 React组件之中,需要极其的小心。这里几乎是更好的选择去使用 ‘resize’ 和 ‘scroll’ 事件 (注: 见下一章节需要注意的事项).

如果你需要使用 setTimeout() or setInterval(), 你必须 遵循下面几个禁令

极其短时间内持续发生不要使用

短时间内持续发生是没有必要使用的,特别是小于100ms的,如果更短的时间内,真的需要,也许你可以使用 [window.requestAnimationFrame()](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) 来代替.

参考这些取消/清除函数

setTimeout() and setInterval()都返回一个唯一的标识符,对于延迟函数,如果有必要可以对其进行取消操作。自从这些函数在全局范围内运行,他们不需要关心你的组件是否已经不在,它会直接导致报错或者停止运行。+

注: 这是真的对于window.requestAnimationFrame()来说

最简单的解决这个问题的方案其实是使用 react-timeoutNPM包,它可以提供高阶组件,确保它能够自动使用上面提到的那个东西,它添加了包裹在组件的props中的setTimeout/setInterval等函数(特别感谢Vixlet开发者Carl Pillot 可戳这里进入)

如果你不希望引入一个依赖,并且想要用你自己的方案去解决这个问题,下面这些可能对你的会有帮助:

如果你在使用requestAnimationFrame()来控制动画循环,你可以使用很小的通知来进行类似的处理。

去抖和防流事件

一定程度上来说,正常的事件是极其迅速的,像”scroll”,”resize”.这是很明智的,去抖事件,特别是如果这些事件被解决的话,远远比那些极其基本的功能执行的好。

Lodash有[_.debounce](https://lodash.com/docs/#debounce) 方法. 这里依然是一个独立的[debounce](https://www.npmjs.com/package/debounce)NPM包

“但是我真的需要scroll/resize/无论什么事件立即响应”

我曾经发现了一种模式可以以一种高性能的方式来解决这类事件响应问题,那就是使用 requestAnimationFrame()来监听事件开始和结束的时间,然后, [debounce()](https://lodash.com/docs#debounce)函数通过使用 trailing选项来设置为 true(这就意味着函数仅仅在节流函数结束之后才结束)来阻止监听这个值,看下面的例子

密集的CPU任务导致线程阻塞

毫无疑问,很多任务一起将会加强CPU的损耗,因此引起主要的渲染阻塞,一些例子包括非常复杂的数学计算,通过一个很大的数组进行迭代,通过使用File api来进行渲染/覆写. 加密或者解密图像数据从`` object中.

如果在所有的情节当中,也许使用web搬运工,将其一些功能性的东西搬移到另外一个线程中会更好,因此,我们的主要渲染进程中能够顺利的进行。

阅读这些

MDN 文章: Using Web Workers

MDN 文档: Worker API

结尾

我们希望你已经发现上面这些有用的建议和信息。最后说一句,如果没有我们的Vixlet团队,上面这些技巧和提示方法是不可能被搜索出来,并且很好的运行的,他们真的是我工作以来,有幸接触到的一群非常优秀的团队伙伴。

在React之外进行升华,持续学习和练习,希望和你一起进步!

谢谢 Matt Lubner

【翻译】光速React – Vixlet的更多相关文章

  1. 光速 React

    光速 React Vixlet 团队优化性能的经验教训 在过去一年多,我们 Vixlet 的 web 团队已经着手于一个激动人心的项目:将我们的整个 web 应用迁移到 React + Redux 架 ...

  2. 【翻译】React vs Angular: JavaScript的双向性

    翻译原文链接:https://blog.prototypr.io/react-vs-angular-two-sides-of-javascript-b850de22b413 我的翻译小站:http:/ ...

  3. 翻译--Thinking in React

    无聊翻译篇react入门文章,去年学习react时看了一遍,很不错的一篇文章. https://reactjs.org/docs/thinking-in-react.html 部分为意译,旨在让new ...

  4. Thinking in React

    本文翻译自React的官方博客,详情请阅读原文. React非常适合构建组件化的应用,它注重高性能,因此组建的重用,项目的扩展都十分灵活,Facebook和instagram的不少商业项目使用了此框架 ...

  5. Cordova VS React Native 谁是未来? - b

    对于原生native还是倍加推崇的,极佳的用户体验和性能让我学的如痴如醉,可是互联网这个世界可以用一句话可以总结:没有什么是不可能的.自从阿里淘宝天猫横空出世,它们教会了人们如何在网上购物,然后仿佛一 ...

  6. React Native 初识

    Facebook 在 React.js Conf 2015 大会上推出了基于 JavaScript 的开源框架 React Native,本中文教程翻译自 React Native 官方文档. Rea ...

  7. Learning React Native笔记

    React Native作为一个新事物,相关的资料还不多 官方的文档比较简单,缺少一些系统的例子 在对React Native的应用中,迫切的想学习一些别人的最佳实践.所以想通过看书系统的学习下 之前 ...

  8. React文档翻译 (快速入门)

    翻译自react的大部分文档,方便自己查阅. 目录 生命周期 实例化 存在期 销毁期 state Do Not Modify State Directly State Updates May Be A ...

  9. 【转】React 常用面试题目与分析

    作者:王下邀月熊链接:https://zhuanlan.zhihu.com/p/24856035来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 本文有一定概率为水文,怕 ...

随机推荐

  1. 详解Executor框架

    在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...

  2. yii框架后台过滤器的使用 安全防护

    Yii过滤器简介 过滤器是一段代码,可被配置在控制器动作执行之前或之后执行.例如, 访问控制过滤器将被执行以确保在执行请求的动作之前用户已通过身份验证:性能过滤器可用于测量控制器执行所用的时间. 一个 ...

  3. 第一次在gitHub上传项目到git.oschina的方法

    首先在Git@osChina创建一个项目仓库 1.创建sshKey公钥 ssh-keygen -t rsa -C "ty635725964@qq.com" 之后连续三个空格,默认无 ...

  4. 函数, lambda表达式

    函数 函数:简单的理解,就是一次执行很多行代码 函数的返回值 函数的参数,和变量没区别 例: def hello(): print "hello world" hello() he ...

  5. 手把手教做单点登录(SSO)系列之一:概述与示例

    本系列将由浅入深的结合示例.源码以及演示视频,手把手的带大家深入最新的单点登录SSO方案选型与架构开发实战.文末附5个满足不同单点登录场景的gif动画演示(如果看不清请在图片上右键用新窗口打开),本系 ...

  6. webService 下得 拦截

    当我们 对webservice 接口的 拦截 更具权限  来 判断 是否可以调用  一下是我的 一个demo 首先 我们写一个 拦截类 import javax.xml.soap.SOAPExcept ...

  7. 安装hexo报错(npm WARN deprecated swig@1.4.2: This package is no longer maintained),已解决

    问题:在使用npm安装hexo时报错 $ npm install -g hexo npm WARN deprecated swig@1.4.2: This package is no longer m ...

  8. 从点击到呈现 — 详解一次HTTP请求

    一般来说,很多的参考资料上面都会说,http 是一个基于请求/响应的工作模式,然后画出一张浏览器和服务器的 b/s 结构图,再画上两个箭头,表示请求和响应,应该说这么解释是易懂的,一般也是够清楚的,但 ...

  9. Python常见的错误汇总

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 错误: [错误分析]第二个参数必须为类,否则会报TypeError,所以正确的应 ...

  10. 倒计时(距离活动结束还有X天X小时X分X秒)

    一个简单的倒计时,可以设定结束时间,然后自动计算出距离活动结束还有X天X小时X分X秒. 废话不多说,上代码,挺简单的,代码里有注释: // 活动倒计时 var time_end = new Date( ...