现代 JavaScript JITers 是否需要在循环中进行数组长度缓存?

发布于 2024-11-14 11:47:33 字数 599 浏览 1 评论 0 原文

我发现在 for 循环中缓存数组的 length 属性的做法非常令人反感。 至少在我看来

for (var i = 0, l = myArray.length; i < l; ++i) {
    // ...
}

,与直接的相比,这会严重损害可读性

for (var i = 0; i < myArray.length; ++i) {
    // ...
}

(更不用说由于词法作用域和提升的性质,它会将另一个变量泄漏到周围的函数中。)

我希望能够告诉任何这样做的人“别打扰;现代 JS JITers 已经优化了这个技巧”。显然,这不是一个微不足道的优化,因为您可以在迭代数组时修改数组,但我认为考虑到我听说过的有关 JITers 及其运行时分析技巧的所有疯狂内容,他们应该通过以下方式实现这一点:现在。

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

是的,我也希望说“这是一个微观优化;在你进行分析之前不要这样做。”但并不是每个人都会听这样的理由,尤其是当缓存长度成为一种习惯时,他们最终会自动这样做,几乎作为一种风格选择。

I find the practice of caching an array's length property inside a for loop quite distasteful. As in,

for (var i = 0, l = myArray.length; i < l; ++i) {
    // ...
}

In my eyes at least, this hurts readability a lot compared with the straightforward

for (var i = 0; i < myArray.length; ++i) {
    // ...
}

(not to mention that it leaks another variable into the surrounding function due to the nature of lexical scope and hoisting.)

I'd like to be able to tell anyone who does this "don't bother; modern JS JITers optimize that trick away." Obviously it's not a trivial optimization, since you could e.g. modify the array while it is being iterated over, but I would think given all the crazy stuff I've heard about JITers and their runtime analysis tricks, they'd have gotten to this by now.

Anyone have evidence one way or another?

And yes, I too wish it would suffice to say "that's a micro-optimization; don't do that until you profile." But not everyone listens to that kind of reason, especially when it becomes a habit to cache the length and they just end up doing so automatically, almost as a style choice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

叫思念不要吵 2024-11-21 11:47:33

这取决于以下几点:

  • 您是否证明您的代码在循环上花费了大量时间
  • 您完全支持的最慢的浏览器是否受益于数组长度缓存
  • 您或处理您代码的人员是否发现数组长度缓存很难 来看

从我见过的基准 似乎如此(例如, 此处此处) IE 中的性能 < ; 9(通常是您必须处理的最慢的浏览器)受益于缓存数组长度,因此可能值得这样做。无论如何,我长期以来都有缓存数组长度的习惯,因此发现它很容易阅读。还有其他可以产生效果的循环优化,例如递减计数而不是递增计数。

以下是 JSMentors 邮件列表中关于此问题的相关讨论:http://groups.google .com/group/jsmentors/browse_thread/thread/526c1ddeccfe90f0

It depends on a few things:

  • Whether you've proven your code is spending significant time looping
  • Whether the slowest browser you're fully supporting benefits from array length caching
  • Whether you or the people who work on your code find the array length caching hard to read

It seems from the benchmarks I've seen (for example, here and here) that performance in IE < 9 (which will generally be the slowest browsers you have to deal with) benefits from caching the array length, so it may be worth doing. For what it's worth, I have a long-standing habit of caching the array length and as a result find it easy to read. There are also other loop optimizations that can have an effect, such as counting down rather than up.

Here's a relevant discussion about this from the JSMentors mailing list: http://groups.google.com/group/jsmentors/browse_thread/thread/526c1ddeccfe90f0

听风念你 2024-11-21 11:47:33

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

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);
}

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

My tests show that all major newer browsers cache the length property of arrays. You don't need to cache it yourself unless you're concerned about IE6 or 7, I don't remember exactly. However, I have been using another style of iteration since those days since it gives me another benefit which I'll describe in the following example:

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);
}

You must realize that this iteration style stops if the array is allowed to contain 'falsy' values, so this style cannot be used in that case.

离鸿 2024-11-21 11:47:33

首先,这为什么更难做到或者更不清晰?

var i = someArray.length;
while(i--){
    //doStuff to someArray[i]
}

这不是什么奇怪的神秘的微优化。这只是一个基本的避免工作原则。不使用“.”或超过必要的“[]”运算符应该与不多次重新计算 pi 一样明显(假设您不知道我们已经在 Math 对象中拥有了它)。

[rantish elements yoinked]

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

但这涉及相当多的复杂性。每次您执行任何改变该数组的操作时,您都必须将 length 视为静态属性,并告诉您的数组更改方法(我的意思是它们的本机代码方面)手动设置该属性,而通常 length 每次都会对项目进行计数参考。这意味着每次添加新的数组更改方法时,您都必须更新 JIT 以分支行为以获取本地作用域数组的长度引用。

我可以看到 Chrome 最终会这样做,但我认为它还没有基于一些真正非正式的测试。我不确定 IE 是否会优先考虑这种级别的性能微调。至于其他浏览器,您可以对维护问题提出强有力的论据,即必须为每个新数组方法进行分支行为,这比其价值更麻烦。至少,不会成为重中之重。

最终,即使在典型的 JS 循环的旧浏览器中,每个循环周期访问 length 属性也不会让您花费太多。但我建议养成缓存多次执行的任何属性查找的习惯,因为使用 getter 属性,您永远无法确定正在完成多少工作,哪些浏览器以什么方式优化或您可以降低什么样的性能成本当有人决定将 someArray 移到函数之外时,这可能会导致调用对象在每次执行该属性访问时都会在十几处位置进行检查,然后才能找到它要查找的内容。

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

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

但真正让我恼火的是,Word 文档现在的加载速度和 1995 年一样慢,而且人们继续编写性能极其缓慢的 Java 网站,尽管 Java 的 VM 据称在性能方面击败了所有非编译的竞争者。我认为你可以让编译器整理性能细节以及“现代计算机是如此之快”这一概念与此有很大关系。在我看来,当工作很容易避免并且不会威胁到易读性/可维护性时,我们应该始终注意避免工作。从长远来看,以不同的方式做事从来没有帮助我(或者我怀疑任何人)更快地编写代码。

First of all, how is this harder to do or less legible?

var i = someArray.length;
while(i--){
    //doStuff to someArray[i]
}

This is not some weird cryptic micro-optimization. It's just a basic work avoidance principle. Not using the '.' or '[]' operators more than necessary should be as obvious as not recalculating pi more than once (assuming you didn't know we already have that in the Math object).

[rantish elements yoinked]

If someArray is entirely internal to a function it's fair game for JIT optimization of its length property which is really like a getter that actually counts up the elements of the array every time you access it. A JIT could see that it was entirely locally scoped and skip the actual counting behavior.

But this involves a fair amount of complexity. Every time you do anything that mutates that Array you have to treat length like a static property and tell your array altering methods (the native code side of them I mean) to set the property manually whereas normally length just counts the items up every time it's referenced. That means every time a new array-altering method is added you have to update the JIT to branch behavior for length references of a locally scoped array.

I could see Chrome doing this eventually but I don't think it is yet based on some really informal tests. I'm not sure IE will ever have this level of performance fine-tuning as a priority. As for the other browsers, you could make a strong argument for the maintenance issue of having to branch behavior for every new array method being more trouble than its worth. At the very least, it would not get top priority.

Ultimately, accessing the length property every loop cycle isn't going to cost you a ton even in the old browsers for a typical JS loop. But I would advise getting in the habit of caching any property lookup being done more than once because with getter properties you can never be sure how much work is being done, which browsers optimize in what ways or what kind of performance costs you could hit down the road when somebody decides to move someArray outside of the function which could lead to the call object checking in a dozen places before finding what it's looking for every time you do that property access.

Caching property lookups and method returns is easy, cleans your code up, and ultimately makes it more flexible and performance-robust in the face of modification. Even if one or two JITs did make it unnecessary in circumstances involving a number of 'ifs', you couldn't be certain they always would or that your code would continue to make it possible to do so.

So yes, apologies for the anti-let-the-compiler-handle-it rant but I don't see why you would ever want to not cache your properties. It's easy. It's clean. It guarantees better performance regardless of browser or movement of the object having its property's examined to an outer scope.

But it really does piss me off that Word docs load as slowly now as they did back in 1995 and that people continue to write horrendously slow-performing java websites even though Java's VM supposedly beats all non-compiled contenders for performance. I think this notion that you can let the compiler sort out the performance details and that "modern computers are SO fast" has a lot to do with that. We should always be mindful of work-avoidance, when the work is easy to avoid and doesn't threaten legibility/maintainability, IMO. Doing it differently has never helped me (or I suspect anybody) write the code faster in the long term.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文