问题

缓存 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. POJ3071:Football(概率DP)

    Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, …, 2 ...

  2. Web页面布局方式小结

    Web页面是由块元素组成的,正常情况下块元素一个个按垂直方向排布,构成了页面.可是这样的主要的布局方式绝大多时候不能满足我们的需求,所以各种布局方式应运而生,本文就对这些布局方式做个小结. 1.元素漂 ...

  3. 数据库学习之ADO.NET五大对象

    1 [ADO.NET]      ado.net 是一种数据访问技术,使得应用程序能够连接到数据存储,并以各种方式操作存储在里面的数据.    2 [ADO.NET五大常用对象]     Connec ...

  4. [转]WCF:如何将net.tcp协议寄宿到IIS

    本文转自:http://www.cnblogs.com/Gyoung/archive/2012/12/11/2812555.html 1 部署IIS 1.1 安装WAS IIS原本是不支持非HTTP协 ...

  5. Linked List Cycle (java)

    public boolean hasCycle(ListNode head) { ListNode slow=head; ListNode fast=head; if(head==null)retur ...

  6. su普通用户切换root用户失败

    http://blog.itpub.net/26432034/viewspace-1688391/ http://blog.csdn.net/zhangdaiscott/article/details ...

  7. Path Sum,Path Sum II

    Path Sum Total Accepted: 81706 Total Submissions: 269391 Difficulty: Easy Given a binary tree and a ...

  8. linux下C++对线程的封装

    之前一直是使用C语言,前段时间转做C++.无论使用什么语言,多线程编程都是不可或缺的.最近项目中又用到了线程,现在将线程的封装做出总结: 1.线程类中应该包含线程ID.线程的状态以及线程基本操作等. ...

  9. 【Android】设备标识简介(imei imsi mac地址)

    IMEI: 1- 意义: 参考http://zh.wikipedia.org/zh-cn/IMEI  国际移动设备辨识码 ,共15位,和厂商,产地等有关. 2- 获取: 直接查看设备信息,设置-关于手 ...

  10. SecureCRT使用的技巧 键盘修改

    secureCRT 修改PageUP,PageDown,Home,End键小trick:http://blog.csdn.net/shark_sq/article/details/6722512 所有 ...