考虑以下代码:
Test = function() {
}
t = new Test();
for (var i = 0; i < 8; i++) {
result = t instanceof Test;
}
如果您将迭代次数从 8 更改为 9 ,则循环将突然显示 100倍以在最近完成Firefox版本(41.0.1)。我在两台不同的PC上进行了测试,魔术限制总是为8。
这是我使用的JSPerf测试: http://jsperf.com/instanceof-8-times-vs-9-times
是否有人知道为什么会发生这种情况?它似乎特定于 instanceof 。如果您对该对象执行其他操作,则不会发生这种情况,例如检查属性。
注意:我还提交了一份Bugzilla bug。
答案 0 :(得分:1)
在i < 8
的情况下,Firefox非常聪明地将result = t instanceof Test;
语句提升出循环(根据我的测试,它似乎并没有完全省略它)。在i < 9
案例中,显然没有进行优化。
为什么呢?原因并不完全清楚,但它可能与9次迭代是一个阈值的事实相关,超过该阈值,该函数被认为足够“热”以通过JIT编译器运行它。 i < 8
案例保留在翻译中。 (我不明白为什么JIT-ing会排除吊装,但显然它在发动机的当前版本中也是如此。)
有趣的是,8次迭代阈值似乎并不普遍。例如,如果我们用内置原型(例如Test
)替换我们自己的原型(CustomEvent
),无论迭代次数多少,都不会发生提升(relevant JSPerf ):
for (var i = 0; i < 8; i++) { //or i < 9
t instanceof CustomEvent;
}
使用Test
原型回到原始代码,为什么在i < 9
情况下性能如此糟糕?这与JSPerf的工作方式有关。 “设置”代码不仅执行一次 - 它每次测试运行一次。每次单击“运行”时,JSPerf都会运行数百个“测试”,每个测试包含数千次迭代。因此设置代码运行数百次。这意味着程序中有数百个不同的原型对象,名为Test
,所有这些对象都是用该行创建的:
Test = function(){
}
Ion JIT优化编译器可以轻松优化我们在同一个原型对象上多次使用instanceof
的情况(就像我们在this test case中对CustomEvent
所做的那样),但< strong>当它注意到有多个具有相同名称的对象时,显然它将手伸向空中。
Jan正确地指出,这不太可能影响太多的真实世界脚本,因为通常单个标识符与单个原型对象相关联(例如,您有一个类Foobar
,它只定义一次并且从未重新定义过)。但JSPerf重新定义了数百次原型。在我看来,这个事实对所有已发布的JSPerf结果(包括原型定义)产生了严重怀疑,除了那些通过使用全局变量明确避免重新定义的结果(如此test case) - 这可能是这一切中最重要的结论。
例如,从这个问题链接的JSPerf测试:Is using instanceof operator in javascript a performance issue?可能毫无价值,因为它们都在设置代码中定义了原型。
答案 1 :(得分:-2)
当值为9时,循环10次,因此100x可能是10 ^ 2 - 即两个字符而不是一个字符。人们还可以确定这样做100次是否会导致10 ^ 3减速。听起来很疯狂,但这个Javascript。