个人常用JavaScript及React常用优化总结

来源:互联网 发布:lte mrr弱覆盖优化 编辑:程序博客网 时间:2024/04/30 11:01

JavaScript 插件性能优化及个人react常用优化方法

http://www.tuicool.com/articles/byiQfam

JavaScript 经常会触发视觉变化。有时是直接通过样式操作,有时是会产生视觉变化的计算,例如搜索数据或将其排序。时机不当或长时间运行的 JavaScript 可能是导致性能问题的常见原因。您应当设法尽可能减少其影响。

JavaScript 性能分析可以说是一门艺术,因为您编写的 JavaScript 代码与实际执行的代码完全不像。现代浏览器使用 JIT 编译器和各种各样的优化和技巧来尝试为您实现尽可能快的执行,这极大地改变了代码的动态。

注:如果您真的想了解 JIT 的实例,应当查看 Vyacheslav Egorov 提供的 IRHydra2。它显示了当 Chrome 的 JavaScript 引擎 V8 对 JavaScript 代码进行优化时,JavaScript 代码的中间状态。

尽管如此,您肯定还是可以做一些事情来帮助您的应用很好地执行 JavaScript。但 Javascript 性能优化绝不是一种书面的技术,借鉴别人的意见和自己平时项目的总结给出以下几条建议:

变量问题

当一个变量被引用的时候,JavaScript将在作用域链中的不同成员中查找这个变量。作 用域链指的是当前作用于下可用变量的集合,它在各种主流浏览器中至少包含两个部分:局部变量的集合和全局变量的集合。

简单地说,如果JavaScript引擎在作用域链中搜索的深度越大,那么操作也就会消耗更多的时间。引擎首先从 this 开始查找局部变量,然后是函数参数、本地定义的变量,最后遍历所有的全局变量。

因为局部变量在这条链的起端,所以查找局部变量总是比查找全局变量要块。所以当你想要不止一次地使用一个全局变量的时候,你应该将它定义成局部变量,就像这样:

var dom1 = document.getElementById('id1'),dom2 = document.getElementById('id2');

改写成

var document = document,demo1 = document.getElementById('id1'),demo2 = document.getElementById('id2');

小心的使用闭包

虽然你可能还不知道“闭包”,但你可能在不经意间经常使用这项技术。闭包基本上被认为是JavaScript中的new,当我们定义一个即时函数的时候,我们就使用了闭包,比如:

document.getElementById('dom').onclick = function(ev) { };

闭包的问题在于:根据定义,在它们的作用域链中至少有三个对象:闭包变量、局部变量和全局变量。这些额外的对象将会导致第1和第2个建议中提到的性能问题。

闭包对于提高代码可读性等方面还是非常有用的,只是不要滥用它们(尤其在循环中)。

对象的属性和数组元素影响

谈到JavaScript的数据,一般来说有4种访问方式:数值、变量、对象属性和数组元素。在考虑优化时,数值和变量的性能差不多,并且速度显著优于对象属性和数组元素。

因此当你多次引用一个对象属性或者数组元素的时候,你可以通过定义一个变量来获得性能提升。(这一条在读、写数据时都有效)

虽然这条规则在绝大多数情况下是正确的,但是Firefox在优化数组索引上做了一些有意思的工作,能够让它的实际性能优于变量。但是考虑到数组元素在其他浏览器上的性能弊端,还是应该尽量避免数组查找,除非你真的只针对于火狐浏览器的性能而进行开发。

不要乱碰DOM

不使用DOM是JavaScript优化中另一个很大的话题。经典的例子是添加一系列的列表项:如果你把每个列表项分别加到DOM中,肯定会比一次性加入所有列表项到DOM中要慢。这是因为DOM操作开销很大。

Zakas对这个进行了细致的讲解,解释了由于回流(reflow)的存在,DOM操作是非常消耗资源的。回流通常被理解为浏览器重新选渲染DOM树的处理过程。比如说,如果你用JavaScript语句改变了一个div的宽度,浏览器需要重绘页面来适应变化。

任何时候只要有元素被添加到DOM树或者从DOM树移除,都会引发回流。使用一个非常方便的JavaScript对象可以解决这个问题——documentFragment,我并没有使用过,但是在Steve Souders也表示同意这种做法之后我感觉更加肯定了。

DocumentFragment 基本上是一种浏览器以非可视方式实现的类似文档的片段,非可视化的表现形式带来了很多优点,最主要的是你可以在 documentFragment 中添加任何结点而不会引起浏览器回流。

不要在数组中挖得太深

另外,程序员应该避免在数组中挖得太深,因为进入的层数越多,操作速度就越慢。

简单地说,在嵌套很多层的数组中操作很慢是因为数组元素的查找速度很慢。试想如果操作嵌套三层的数组元素,就要执行三次数组元素查找,而不是一次。

因此如果你不断地引用 foo.bar, 你可以通过定义 var bar = foo.bar 来提高性能。

定时器的使用

如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval,因为setTimeout每一次都会初始化一个定时器,而setInterval只会在开始的时候初始化一个定时器。

var timeoutTimes = 0;        function timeout() {            timeoutTimes++;            if (timeoutTimes < 10) {                setTimeout(timeout, 10);            }        }        timeout();        //可以替换为:        var intervalTimes = 0;        function interval() {            intervalTimes++;            if (intervalTimes >= 10) {                clearInterval(interv);            }        }        var interv = setInterval(interval, 10);

React上的性能优化

对于小型react前端应用,最好的优化就是不优化因为React本身就是通过比较虚拟DOM的差异,从而对真实DOM进行最小化操作,小型React应用的虚拟DOM结构简单,虚拟DOM比较的耗时可以忽略不计。而对于复杂的前端项目,我们所指的渲染性能优化,实际上是指,在不需要更新DOM时,如何避免虚拟DOM的比较。

  1. react组件的生命周期

    工欲善其事,必先利其器。理解react的组件的生命周期是优化其渲染性能的必备前提。我们可以将react组件的生命周期分为3个大循环:挂载到DOM、更新DOM、从DOM中卸载。React对三个大循环中每一步都暴露出钩子函数,使得我们可以细粒度地控制组件的生命周期。
    • 挂载到DOM

      组件首次插入到DOM时,会经历从属性和状态初始化到DOM渲染等基本流程,可以通过下图所示

必须注意的是,挂载到DOM流程在组件的整个生命周期只有一次,也就是组件第一次插入DOM文档流时。在挂载到DOM流程中的每一步也有相应的限制:
  • 更新DOM

    组件挂载到DOM后,一旦其props和state有更新,就会进入更新DOM流程。同样我们也可以通过一张图清晰的描述该流程的各个步骤:
    //getDefaultProps()和getInitialState()中不能获取和设置组件的state。//render()方法中不能设置组件的state。

    componentWillReceiveProps()提供了该流程中更新state的最后时机,后续的其他函数都不能再更新组件的state了。我们尤其需要注意的是shouldComponentUpdate函数,它的结果直接影响该组件是不是需要进行虚拟DOM比较,我们对组件渲染性能优化的基本思路就是:在非必要的时候将shouldComponentUpdate返回值设置为false,从而终止更新DOM流程中的后续步骤。
  • 从DOM中卸载

    从DOM中卸载的流程比较简单,React只暴漏出componentWillUnmount,该函数使得我们可以在DOM卸载的最后时机对其进行干预。

2、性能分析

合理的使用shouldComponentUpdate()可以在很大程序上优化应用。但在实际情况下,应用往往在沙箱或是开发环境中运行的非常快,但生产环境则表现的不尽人意。这时,我们需要对应用进行性能分析,然后再有针对性的在shouldComponentUpdate()中进行优化。React 提供了性能分析插件React.addons.Perf,它让我们可以在需要检测的代码起始位置分别添加Perf.start()和Perf.stop(),并可以通过Perf.printInclusive()方法打印花费时间,然后我们可以结合数据做进一步的分析。React.addons.Perf插件的详细用法,可以查看官方文档。

3、 借助react Key标识组件

key属性在组件类之外提供了另一种方式的组件标识。通过key标识我们可以组件如:顺序改变、不必要的子组件更新等情况下,告诉React 避免不必要的渲染而避免性能的浪费。

如,对于如一个基于排序的组件渲染

var items = sortBy(this.state.sortingAlgorithm, this.props.items);return items.map(function(item){  return <img src={item.src} />});

当顺序发生改变时,React 会对元素进行diff操作,并改img的src属性。显示,这样的操作效率是非常低的。这时,我们可以为组件添加一个key属性以唯一的标识组件:

return <img src={item.src} key={item.id} />
0 0
原创粉丝点击