问题

缓存 Array.length 是老生常谈的小优化。

// 不缓存
for (var i = 0; i < arr.length; i++) {
...
} // 缓存
var len = arr.length;
for (var i = 0; i < len; i++) {
...
} // 或者
for (var i = 0, len = arr.length; i < len; i++) {
...
}

但以前写过 Java 的笔者一直对这种破碎的写法感到不适,也对这种写法的实际优化效果产生疑问。

且推崇这种写法的朋友似乎很多也是“前辈这么说+自己想了一下觉得有道理”。

由于 for 循环搭配 Array.length 是极度常用的 JavasScript 代码,所以还是有必要搞清楚的。

结论

经过一番摸索后笔者得到的结论是:缓存 Array.lengh 对优化的影响没有想象中的大,甚至可能会有所减慢。

理由

从测试结果上看

stackoverflow 上也有这个讨论,For-loop performance: storing array length in a variable 。

accepted 的答案是说缓存会起到加速的结果,给出了 jsPerf 测试。

但是有答案反对,也给出了 jsPerf 测试。

两个答案的区别在于“循环不变量代码移动(Loop-invariant code motion)”,accepted 答案的测试循环里没有访问到数组,是不实际的,后面会讲到。

从另一篇文章 Shoud I have to cache my array’s length? 的测试结果也可以看出缓存差别不大。

还有这篇 JavaScript's .length Property is a Stored Value

从 V8 的中间代码分析

这篇文章 How the Grinch stole array.length access 从 V8 的 hydrogen 探讨 Array.length 在 for 循环中的处理。

正如上面提到的“循环不变量代码移动”,V8 引擎会聪明的把能确定不变的代码移到循环外。

所以像下面这种代码也不会影响引擎对 Array.length 的优化:

function uncached(arr) {
for (var i = 0; i < arr.length; i++) {
arr[i]
}
}

而当在循环中调用函数时,V8 会尝试将函数进行内联,从而继续进行“循环不变量代码移动”优化。
但当函数不可内联时,V8 就没辙了,每次循环都要重新计算一遍 length

function BLACKHOLE(sum, arr) {
try { } catch (e) { }
} function uncached(arr) {
var sum = 0;
for (var i = 0; i < arr.length; i++) {
sum += arr[i];
if (sum < 0) BLACKHOLE(arr, sum);
}
return sum;
}

但这时即便是在循环外缓存了 length 也是没有用的,引擎没法预判数组的变化,当需要访问数组元素时会触发 bounds check ,从而照样要计算一遍 length 。所以缓存 length 是没有用的。

甚至,由于多了一个变量,底层的寄存器分配器每次循环还要多一次恢复这个变量。当然这个只有在大规模的情况下才会看出区别。

结尾

当然这篇文章也有局限性,仅仅讨论了 V8 引擎,也没有讨论访问 length 代价更高的 HTMLCollection 。但这已经足够说明两者差别不大,一般情况下我们不用再局限于缓存的写法,可以放开来按照自己喜欢的方式去写循环了。

【完】

原文:http://div.io/topic/966

缓存 Array.length 是老生常谈的小优化的更多相关文章

  1. check the element in the array occurs more than half of the array length

    Learn this from stackflow. public class test { public static void main(String[] args) throws IOExcep ...

  2. [Bug]The maximum array length quota (16384) has been exceeded while reading XML data.

    写在前面 在项目中,有客户反应无法正常加载组织结构树,弄了一个测试的程序,在日志中查看到如下信息: Error in deserializing body of reply message for o ...

  3. SPFA 小优化*2

    /* bzoj 2763 SPFA小优化 循环队列+SLF 顺面改掉自己之前手打qeueu的坏毛病*/ #include<iostream> #include<cstring> ...

  4. Array.length vs Array.prototype.length

    I found that both the Array Object and Array.prototype have the length property. I am confused on us ...

  5. 【转】The magic behind array length property

    Developer deals with arrays every day. Being a collection, an important property to query is the num ...

  6. [MySQL5.6] 最近对group commit的小优化

    [MySQL5.6] 最近对group commit的小优化 http://www.tuicool.com/articles/rEZr2q 最近花了一些时间在做MySQL Group Commit的优 ...

  7. Count and Say (Array Length Encoding) -- LeetCode

    The count-and-say sequence is the sequence of integers beginning as follows:1, 11, 21, 1211, 111221, ...

  8. SPFA的小优化

    标签:闲扯 SPFA的小优化 1. 向队尾加入元素时,如果它比对首还优,就把把它直接和队首交换. 拿一个双端队列来实现 (手写 , head ,tail   STLdeque亲测及其慢) 这个小优化其 ...

  9. Math.floor(Math.random() * array.length),splice

    1.Math.floor(Math.random() * array.length) 返回长度内的索引 eg: changeLimit () { function getArrayItems(arr, ...

随机推荐

  1. Tomcat可以在eclipse里启动,可是不能訪问首页的问题

    今天在使用eclipse的时候发现一个问题.就是我在eclipse里面已经启动了tomcat.部署上去的项目也能够启动,可是就是没法訪问tomcat的首页.port等等都没有问题. 后来查到解决方式, ...

  2. 检查ORACLE的警告文件的脚本

    检查两天内的须要重视的信息: vi   alter_error.sh echo "Check Alter Error:" cat $TRACE/alert_$ORACLE_SID. ...

  3. RMAN备份各种物理文件

    RMAN运行脚本的方式:RMAN TARGET / @backup_db.rmanRMAN TARGET / cmdfile=backup_db.rman在RMAN中执行操作系统中保存的脚本:RMAN ...

  4. AlertDialog详解

    参考地址:http://blog.csdn.net/woaieillen/article/details/7378324 1.弹出提示框 new AlertDialog.Builder(LoginAc ...

  5. WLW 截屏插件

    转载:http://www.xtit.net/post/1030/ 一直以来用WLW更新博客,刚刚在DailyApps看到一个关于Windows Live Writer的截屏插件,相当不错. 是由MS ...

  6. sql server数据库区分大小写设置

    数据库表中字段alter Table TableName 区分大小写 ALTER Column ColumnName VARCHAR(50) COLLATE Chinese_PRC_CS_AS不区分大 ...

  7. git-svn 的使用

    从 SVN 克隆代码 git svn clone https://192.168.1.3/svn/project-name   git-svn 初始化 git svn init (svn remote ...

  8. Dubbo使用详解及环境搭建

    一:Dubbo简介 Dubbo是阿里巴巴提供的开源的SOA(面向服务的体系结构)服务化治理的技术框架,据说只是一部分开源的,但一些基本的需求已经可以满足的,而且可扩展性.是一种能取代PHRPC的服务调 ...

  9. rotate.js实现图片旋转 (chrome,IE,firefox都可以实现)

    找了好多资料,要么是IE可以用,但是谷歌不行,,还有就是两个都可以用的,图片大小显示不全.终于找到一个好一点的js,先贴一下代码. 1.rotate.js jQuery.fn.rotate = fun ...

  10. Nginx 配置指令的执行顺序(七)

    来看一个 ngx_static 模块服务磁盘文件的例子.我们使用下面这个配置片段:     location / {        root /var/www/;    } 同时在本机的 /var/w ...