现代JavaScript JITER是否需要循环中的数组长度缓存?

现代JavaScript JITER是否需要循环中的数组长度缓存?,javascript,optimization,loops,jit,Javascript,Optimization,Loops,Jit,我发现在for循环中缓存数组的length属性的做法非常令人讨厌。如: for (var i = 0, l = myArray.length; i < l; ++i) { // ... } for(变量i=0,l=myArray.length;i

我发现在
for
循环中缓存数组的
length
属性的做法非常令人讨厌。如:

for (var i = 0, l = myArray.length; i < l; ++i) {
    // ...
}
for(变量i=0,l=myArray.length;i
至少在我看来,与直截了当的内容相比,这对可读性有很大的伤害

for (var i = 0; i < myArray.length; ++i) {
    // ...
}
for(变量i=0;i
(更不用说,由于词法范围和提升的性质,它将另一个变量泄漏到周围的函数中。)

我希望能够告诉做这件事的任何人“不要麻烦,现代JS JITers会把这个技巧优化掉。”显然这不是一个简单的优化,因为你可以在数组被迭代时修改它,但是我想,考虑到我所听到的关于JITER及其运行时分析技巧的疯狂的东西,他们现在应该已经做到了

有人有这样或那样的证据吗


是的,我也希望能说“这是一个微观优化;在你分析之前不要这样做。”但不是每个人都会听这种原因,特别是当缓存长度成为一种习惯,他们只是自动这样做的时候,几乎是一种样式选择。

我的测试表明,所有主要的较新浏览器都缓存数组的长度属性。你不需要自己缓存它,除非你关心IE6或IE7,我记不清了。然而,从那时起,我一直在使用另一种迭代方式,因为它给了我另一个好处,我将在下面的示例中描述:

var arr = ["Hello", "there", "sup"];
for (var i=0, str; str = arr[i]; i++) {
  // I already have the item being iterated in the loop as 'str'
  alert(str);
}

您必须意识到,如果允许数组包含“falsy”值,则此迭代样式将停止,因此在这种情况下不能使用此样式。

这取决于以下几点:

  • 你是否已经证明你的代码在循环上花费了大量的时间
  • 您完全支持的最慢的浏览器是否受益于阵列长度缓存
  • 无论是您还是编写代码的人员都觉得数组长度缓存很难读取
从我所看到的基准测试(例如,和)来看,IE<9的性能(通常是您必须处理的最慢的浏览器)得益于缓存数组长度,因此这可能是值得的。值得一提的是,我有一个长期以来缓存数组长度的习惯,因此很容易阅读。还有其他一些循环优化也会产生影响,比如倒计时而不是倒计时


以下是JSMentors邮件列表中关于这一点的相关讨论:

首先,这一点如何更难做到或更不清晰

var i = someArray.length;
while(i--){
    //doStuff to someArray[i]
}
这不是什么奇怪的神秘的微观优化。这只是一个基本的避免工作的原则。如果不使用“.”或“[]”运算符,那么显然不需要多次重新计算pi(假设您不知道我们在Math对象中已经有了它)

[狂妄自大的人在胡言乱语]

如果某个数组完全是函数内部的,那么对其长度属性进行JIT优化是公平的,这就像一个getter,每次访问它时都会对数组的元素进行计数。JIT可以看到它完全是局部范围的,并且跳过了实际的计数行为

但这涉及相当多的复杂性。每次你做任何改变数组的事情时,你都必须把长度当作一个静态属性来对待,并告诉你的数组改变方法(我指的是它们的本机代码端)手动设置属性,而通常情况下,每次引用它时,长度只计算项目数。这意味着每次添加新的数组更改方法时,都必须更新局部作用域数组的长度引用的JIT到分支行为

我可以看到Chrome最终会这样做,但我不认为它是基于一些真正非正式的测试。我不确定IE是否会优先进行这种级别的性能微调。对于其他浏览器,您可以为维护问题提出强有力的论据,因为每一个新的数组方法都需要分支行为,这是一个非常麻烦的问题。至少,它不会得到最高优先权

最终,即使在旧浏览器中,对于一个典型的JS循环,访问每个循环周期的长度属性也不会花费你很多钱。但我建议你养成一种习惯,即缓存多次执行的任何属性查找,因为使用getter属性,你永远无法确定完成了多少工作,当有人决定将某个数组移到函数之外时,会导致调用对象在十几个地方进行检查,然后在每次执行属性访问时都会找到它要查找的内容,那么哪些浏览器会以何种方式进行优化,或者会降低性能成本

缓存属性查找和方法返回很容易,可以清理代码,并最终使其在面对修改时更灵活、性能更健壮。即使一个或两个JIT确实使它在涉及许多“如果”的情况下变得不必要,您也无法确定它们总是会这样做,或者您的代码会继续使它成为可能

所以,是的,我为反让编译器处理它道歉,但我不明白为什么你不想缓存你的属性。这很容易。它很干净。它保证了更好的性能,无论浏览器或对象的移动是否将其属性检查到外部范围

但现在Word文档的加载速度和1995年一样慢,人们继续编写性能极低的java网站,尽管java的虚拟机在性能上超过了所有未编译的竞争者,这确实让我很恼火。我认为,你可以让编译器整理性能细节,而“现代计算机速度如此之快”与此有很大关系。当工作很容易避免,而且不可能完成时,我们应始终注意避免工作