JavaScript 高效运行代码分析(3)

字符串合并是比较慢的。+ 运算符并不管是否将结果保存在变量中。它会创建新 string 对象,并将结果赋给此对象;也许新对象会被赋给某个变量。下面是一个常见的字符串合并语句:

复制代码 代码如下:

a += 'x' + 'y';

此代码首先创建临时string对象保存合并后的'xy'值,然后和a变量合并,最后将结果赋给a。下面的代码使用两条分开的命令,但每次都直接赋值给a ,因此不需要创建临时string对象。结果在大部分浏览器中,后者比前者快20%,而且消耗更少的内存:

复制代码 代码如下:

a += 'x'; a += 'y';

基本运算符比函数调用更快

尽管单独使用效果不明显,但如果在需要高性能的关键循环和函数中使用基本运算符代替函数调用将可能提高脚本性能。例子包括数组的 push 方法,其效率低于直接在数组末位赋值。另一个例子是 Math 对象方法,大部分情况下,简单的数学运算符效率更高更合适。

复制代码 代码如下:

var min = Math.min(a,b); A.push(v);

下面代码实现相同功能,但效率更高:

复制代码 代码如下:

var min = a < b ? a : b; A[A.length] = v;

向 setTimeout() 和 setInterval()传送函数名,而不要传送字符串

setTimeout() 和 setInterval() 方法近似于 eval。如果传进参数是字符串,则在一段时间之后,会和 eval一样执行字符串值,当然其低效率也和 eval 一样。

但这些方法也可以接受函数作为第一个参数。在一段时间后将调用此函数,但此函数可在编译时被解释和优化,也就是说会有更好的性能。典型的使用 string 作为参数例子如下:

复制代码 代码如下:

setInterval('updateResults()',1000); setTimeout('x+=3;prepareResult();if(!hasCancelled){runmore();}',500);

第一个语句可以直接传递函数名。第二个语句中,可以使用匿名函数封装代码:

setInterval(updateResults,1000); setTimeout(function () { x += 3; prepareResult(); if( !hasCancelled ) { runmore(); } },500);

需要注意的是 timeout或时间延迟可能并不准确。通常浏览器会花比要求更多的时间。有些浏览器会稍微提早完成下一个延迟以补偿。有些浏览器每次可能都会等待准确时间。很多因素,如 CPU 速度、线程状态和 JavaScript负载都会影响时间延迟的精度。大多数浏览器无法提供1ms以下的延迟,可能会设置最小可能延迟,通常在10 和 100 ms之间。

DOM

通常主要有三种情况引起 DOM 运行速度变慢。第一就是执行大量 DOM 操作的脚本,如从获取的数据中建造新的 DOM 树。第二种情况是脚本引起太多的 reflow 或重绘。第三种情况是使用较慢的 DOM 节点定位方法。

第二种和第三种情况比较常见且对性能影响比较严重,因此先介绍前两种情况。

重绘(Repaint)和 reflow

重绘也被称为重画,每当以前不可见的元素变得可见(或反之)时就需要重绘操作;重绘不会改变页面布局。如给元素添加轮廓、改变背景颜色、改变样式。重绘对性能影响很大,因为需要脚本引擎搜索所有元素以确定哪些是可见的及哪些是应被显示的。

Reflow 是更大规模的变化。当 DOM 数被改变时、影响布局的样式被修改时、当元素的 className属性被修改时或当浏览器窗口大小变化时都会引起 reflow。脚本引擎必须 reflow 相关元素以确定哪些部分不应被现实。其子节点也会被reflow 以考虑其父节点的新布局。DOM 中此元素之后出现的元素也被 reflow以计算新布局,因为它们的位置可能已被移动了。祖先节点也需要 reflow 以适应子节点大小的改变。总之,所有元素都需被重绘。

Reflow 从性能角度来说是非常耗时的操作,是导致 DOM 脚本较慢的主要原因之一,特别在手机等处理能力较弱的设备上。很多情况下,reflow 和重新布局整个网页耗时相近。

减少 reflow 次数

很多情况下脚本需要进行会引起 reflow 或重绘的操作,如动画就需要 reflow 操作,因此 reflow 是 Web 开发不可或缺的特性。为了让脚本能快速运行,应在不影响整体视觉效果的情况下尽量减少 reflow 次数。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdsjzs.html