Чому значення typeof null змінюється всередині циклу?


109

Виконання цього фрагмента в консолі Chrome:

function foo() {
    return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());

слід надрукувати 1000 разів false, але на деяких машинах буде надруковано falseдля ряду ітерацій, то trueдля решти.

введіть тут опис зображення

Чому це відбувається? Це просто помилка?


4
Це повертається в 1000 разів для мене ...
Хоанг Довгий

2
я думаю, що це помилка, у мене 262 false / 738 true
Jax Teller

1
це щось дивне з хромованою консоллю: якщо ви натиснете на масив і введіть масив, це все false. як-є, кількість trues коливається в хромі.
dandavis

1
@ HoàngLong, як я вже говорив у запитанні, це відбувається лише на деяких машинах. Можливо також, що це трапляється лише на деяких версіях Chrome
Agos

2
@ HoàngLong переконайтеся, що ви запускаєте його в Chrome
Nobita

Відповіді:


74

Для цього відкрита хромова помилка:

Випуск 604033 - компілятор JIT, що не зберігає поведінку методу

Так так, це просто помилка!


5
"Просто"? Не вдалося це зламати довільні веб-додатки у всьому світі?
jpmc26

6
"Просто" лише сказати, що це не особливість чи щось дивне. Це критична помилка, але просто помилка!
Slumber86

37

Це фактично помилка двигуна V8 JavaScript ( Wiki ).

Цей двигун використовується в Chromium, Maxthron, Android OS, Node.js тощо.

Порівняно простий опис помилок ви можете знайти в цій темі Reddit :

Сучасні двигуни JavaScript компілюють JS-код в оптимізований машинний код при його виконанні (компіляція Just In Time), щоб зробити його швидшим. Однак крок оптимізації має деяку початкову вартість продуктивності в обмін на тривалу швидкість, тому двигун динамічно вирішує, чи варто метод того, залежно від частоти його використання.

У цьому випадку виявляється помилка лише в оптимізованому шляху, тоді як неоптимізований шлях працює добре. Тож спочатку метод працює за призначенням, але якщо він викликається в циклі досить часто в якийсь момент, двигун вирішить його оптимізувати і замінить його на баггі-версію.

Здається, ця помилка була виправлена ​​у самій V8 ( фіксація ), а також у Chromium ( звіт про помилку ) та NodeJS ( фіксація ).


Я підтвердив, що помилка все ще знаходиться в Node.js 6.2.2, що мене хвилює.
Майкл Шопсін

Це було виправлено у двигуні V8 сьогодні (21.06), я вважаю, що незабаром відповідне програмне забезпечення буде оновлено.
Сергій Новіков

Бекпорт на v8 виправлення на Node.js 6.2.x вже йде як питання # 7348 належить TheAlphaNerd .
Майкл Шопсін

18

Щоб відповісти на пряме запитання, чому вона змінюється, помилка знаходиться в рутині оптимізації "JIT" двигуна V8 JS, який використовується Chrome. Спочатку код виконується точно так само, як написано, але чим більше ви його запускаєте, тим більше можливостей для переваг оптимізації перевершити витрати на аналіз.

У цьому випадку після повторного виконання в циклі компілятор JIT аналізує функцію та замінює її оптимізованою версією. На жаль, аналіз робить неправильне припущення, а оптимізована версія насправді не дає правильного результату.

Зокрема, користувач Reddit RainHappens припускає, що це помилка в поширенні типу :

Він також здійснює деякий тип розповсюдження (як у тих, які типи можуть бути змінними тощо). Існує особливий тип "невизначення", коли змінна не визначена або нульова. У цьому випадку оптимізатор переходить "null" не виявляється, тому його можна замінити рядком "undefined" для порівняння.

Це одна з важких проблем оптимізації коду: як гарантувати, що перероблений для продуктивності код все одно матиме такий же ефект, як і оригінал.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.