在Chrome控制台中执行此代码段:
function foo() {
return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());
应打印1000次false
,但在某些计算机上会打印false
一段时间,然后再true
。
为什么会这样?这只是一个错误吗?
答案 0 :(得分:74)
答案 1 :(得分:37)
它实际上是一个V8 JavaScript引擎(Wiki)错误。
此引擎用于Chromium,Maxthron,Android OS,Node.js等。
您可以在此bug description找到相对简单的Reddit topic:
现代JavaScript引擎将JS代码编译为优化的机器代码 执行时(Just In Time编译)使其运行得更快。 但是,优化步骤具有一些初始性能成本 交换长期加速,因此引擎动态决定 一种方法是否值得,取决于它的使用频率。
在这种情况下,仅在优化路径中出现错误, 而未优化的路径工作正常。所以起初这个方法就像 打算,但是如果它在一个循环中被调用,那么在某些时候它就足够了 引擎将决定对其进行优化并将其替换为越野车 版本
此错误似乎已在V8本身(commit)以及Chromium(bug report)和NodeJS(commit)中得到修复。
答案 2 :(得分:18)
为了回答它为何发生变化的直接问题,该错误发生在Chrome使用的V8 JS引擎的“JIT”优化例程中。首先,代码的运行与编写完全相同,但运行得越多,优化的好处就越有可能超过分析成本。
在这种情况下,在循环中重复执行后,JIT编译器会分析该函数,并将其替换为优化版本。不幸的是,分析假设不正确,优化版本实际上并没有产生正确的结果。
具体而言,Reddit user RainHappens suggests 类型传播中的错误:
它还进行某种类型的传播(如变量等可以是什么类型)。当变量未定义或为null时,有一种特殊的“不可检测”类型。在这种情况下,优化器“无法检测到null,因此可以将其替换为”未定义“字符串以进行比较。
这是优化代码的难题之一:如何保证为性能重新排列的代码仍然具有与原始代码相同的效果。
答案 3 :(得分:1)
这是两个月前修复的,很快就会登陆Chrome(已经在Canary)了。
V8 Issue 1912553002 - Fix 'typeof null' canonicalization in crankshaft
Chromium Issue 604033 - JIT compiler not preserving method behavior