Angular有以下有趣的function implementation,它不是循环遍历值数组,而是将它们作为参数并执行if
内联检查。我认为它是出于性能目的而完成的,所以我创建了this simple performance test:
function checkAndUpdateTextInline(v, def, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
let changed = false;
const bindings = def.bindings;
const bindLen = bindings.length;
if (bindLen > 0 && checkAndUpdateBinding(v, def, 0, v0)) changed = true;
if (bindLen > 1 && checkAndUpdateBinding(v, def, 1, v1)) changed = true;
if (bindLen > 2 && checkAndUpdateBinding(v, def, 2, v2)) changed = true;
if (bindLen > 3 && checkAndUpdateBinding(v, def, 3, v3)) changed = true;
if (bindLen > 4 && checkAndUpdateBinding(v, def, 4, v4)) changed = true;
if (bindLen > 5 && checkAndUpdateBinding(v, def, 5, v5)) changed = true;
if (bindLen > 6 && checkAndUpdateBinding(v, def, 6, v6)) changed = true;
if (bindLen > 7 && checkAndUpdateBinding(v, def, 7, v7)) changed = true;
if (bindLen > 8 && checkAndUpdateBinding(v, def, 8, v8)) changed = true;
if (bindLen > 9 && checkAndUpdateBinding(v, def, 9, v9)) changed = true;
return changed;
}
与动态版:
function checkAndUpdateTextDynamic(v, def, values) {
const bindings = def.bindings;
let changed = false;
for (let i = 0; i < values.length; i++) {
if (checkAndUpdateBinding(v, def, i, values[i])) {
changed = true;
}
}
}
内联版似乎比动态快25%。可能是什么原因? inline caching在这里玩吗?如何使用d8
调试它?
答案 0 :(得分:4)
首先,这两个版本不相同:迭代次数在第一个版本中由bindings.length
界定,在第二个版本中由values.length
界定。如果它们不同,您可能会得到不同的迭代次数。
其次,展开版本有几个操作可以避免:
values.length
。values[i]
。i
。i
。前两个特别昂贵,具体取决于编译器能够执行的动态优化和专业化的数量。如果checkAndUpdateBinding
做得不多,那可能是一个明显的开销。您可以尝试更改原始版本以使用其中一些操作,并查看将其放在比较中的位置。
第三,这是一个微观基准。 JavaScript中的性能涉及如此多的隐藏变量以及对静态和动态上下文的依赖性,微基准测试比其他语言更无意义。总的来说,我估计人们对jsperf测量的内容中有90%是无用的,甚至是误导性的。
第四,请注意,循环展开是编译器执行的相当常见的优化。在某些情况下,即使在比JavaScript更有效的语言中,它也可能是一个重要的胜利。
答案 1 :(得分:1)
没有循环,就不需要更新或比较i
(它不存在)。使用Array.prototype.length
时,某些实现可能会很慢。
优化器也可以使用展开的版本,因为它具有固定数量的步骤。优化器不知道values
是1项,10项,100项还是1000万项。