เหตุใดค่าของ typeof null จึงเปลี่ยนไปภายในลูป


109

การเรียกใช้ข้อมูลโค้ดนี้ในคอนโซล Chrome:

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

ควรพิมพ์ 1,000 ครั้งfalseแต่ในบางเครื่องจะพิมพ์falseซ้ำหลายครั้งจากนั้นtrueส่วนที่เหลือ

ใส่คำอธิบายภาพที่นี่

เหตุใดจึงเกิดขึ้น มันเป็นเพียงข้อผิดพลาด?


4
มันกลับมา 1,000 ครั้งจริงสำหรับฉัน ...
Hoàng Long

2
ฉันคิดว่ามันเป็นข้อผิดพลาดฉันมี 262 เท็จ / 738 จริง
Jax Teller

1
มันเป็นสิ่งที่แปลกกับคอนโซลของโครเมี่ยม: falseถ้าคุณผลักดันไปยังอาร์เรย์และเข้าสู่ระบบอาร์เรย์ก็ทั้งหมด ตามที่เป็นอยู่จำนวนtrues ผันผวนในโครเมี่ยม
dandavis

1
@ HoàngLongตามที่ผมพูดในคำถามมันเกิดขึ้นเฉพาะบางเครื่อง นอกจากนี้ยังเป็นไปได้ว่ามันเกิดขึ้นเฉพาะในบางรุ่นของ Chrome
Agos

2
@ HoàngLongให้แน่ใจว่าคุณใช้งานใน Chrome
โนบิตะ

คำตอบ:


74

มีข้อผิดพลาดโครเมียมเปิดสำหรับสิ่งนี้:

ปัญหา 604033 - คอมไพเลอร์ JIT ไม่รักษาลักษณะการทำงานของวิธีการ

ใช่มันเป็นเพียงข้อผิดพลาด!


5
"แค่"? สิ่งนี้จะทำลายเว็บแอปพลิเคชันทั่วโลกโดยพลการไม่ได้หรือ
jpmc26

6
"เพียง" เท่านั้นที่จะบอกว่าไม่ใช่คุณสมบัติหรือสิ่งที่แปลกประหลาด เป็นข้อบกพร่องที่สำคัญ แต่เป็นเพียงข้อบกพร่อง!
Slumber86

37

มันเป็นบั๊กV8 JavaScript engine ( Wiki )

เอ็นจิ้นนี้ใช้ใน Chromium, Maxthron, Android OS, Node.js เป็นต้น

คำอธิบายข้อผิดพลาดค่อนข้างง่ายที่คุณสามารถพบได้ในหัวข้อ Reddit นี้ :

เอ็นจิ้น JavaScript สมัยใหม่จะรวบรวมโค้ด JS เป็นโค้ดเครื่องที่ปรับให้เหมาะสมเมื่อถูกเรียกใช้งาน (การคอมไพล์แบบ Just In Time) เพื่อให้ทำงานได้เร็วขึ้น อย่างไรก็ตามขั้นตอนการปรับให้เหมาะสมมีต้นทุนประสิทธิภาพเริ่มต้นบางส่วนเพื่อแลกกับการเร่งความเร็วในระยะยาวดังนั้นเครื่องยนต์จะตัดสินใจแบบไดนามิกว่าวิธีการใดคุ้มค่าหรือไม่ขึ้นอยู่กับว่าใช้กันทั่วไปเพียงใด

ในกรณีนี้ดูเหมือนจะมีข้อบกพร่องเฉพาะในเส้นทางที่ปรับให้เหมาะสมเท่านั้นในขณะที่เส้นทางที่ไม่ได้เพิ่มประสิทธิภาพจะทำงานได้ดี ดังนั้นในตอนแรกวิธีการนี้จะได้ผลตามที่ตั้งใจไว้ แต่ถ้ามันถูกเรียกแบบวนซ้ำบ่อยพอในบางจุดเครื่องยนต์จะตัดสินใจเพิ่มประสิทธิภาพและแทนที่ด้วยเวอร์ชันบั๊กกี้

ข้อผิดพลาดนี้ดูเหมือนจะได้รับการแก้ไขแล้วใน V8 เอง ( กระทำ ) เช่นเดียวกับใน Chromium ( รายงานข้อผิดพลาด ) และ NodeJS (คอมมิต )


ฉันยืนยันว่าบั๊กยังอยู่ใน Node.js 6.2.2 ซึ่งทำให้ฉันกังวล
Michael Shopsin

ได้รับการแก้ไขในเครื่องยนต์ V8 ในวันนี้ (21.06) ฉันเชื่อว่าซอฟต์แวร์ที่เกี่ยวข้องจะได้รับการอัปเดตในไม่ช้า
Sergey Novikov

backporting การแก้ไข v8 เพื่อ Node.js 6.2.x ที่มีอยู่แล้วในความคืบหน้าเป็นปัญหา# 7348เป็นเจ้าของโดยTheAlphaNerd
Michael Shopsin

18

เพื่อตอบคำถามโดยตรงว่าเหตุใดจึงเปลี่ยนแปลงข้อบกพร่องอยู่ในรูทีนการเพิ่มประสิทธิภาพ "JIT" ของเครื่องมือ V8 JS ที่ Chrome ใช้ ในตอนแรกโค้ดจะทำงานตรงตามที่เขียนไว้ แต่ยิ่งคุณเรียกใช้มากเท่าไหร่ก็ยิ่งมีศักยภาพมากขึ้นสำหรับประโยชน์ของการเพิ่มประสิทธิภาพเพื่อให้มีค่ามากกว่าต้นทุนในการวิเคราะห์

ในกรณีนี้หลังจากดำเนินการซ้ำในลูปคอมไพลเลอร์ JIT จะวิเคราะห์ฟังก์ชันและแทนที่ด้วยเวอร์ชันที่ปรับให้เหมาะสม น่าเสียดายที่การวิเคราะห์ทำให้สมมติฐานที่ไม่ถูกต้องและเวอร์ชันที่ปรับให้เหมาะสมไม่ได้ให้ผลลัพธ์ที่ถูกต้อง

โดยเฉพาะผู้ใช้ Reddit RainHappens แนะนำว่าเป็นข้อผิดพลาดในการเผยแพร่ประเภท :

นอกจากนี้ยังทำการขยายพันธุ์บางประเภท (เช่นเดียวกับตัวแปรประเภทใดเป็นต้น) มีประเภทพิเศษ "ตรวจไม่พบ" เมื่อตัวแปรไม่ได้กำหนดหรือเป็นโมฆะ ในกรณีนี้เครื่องมือเพิ่มประสิทธิภาพจะเปลี่ยนเป็น "null is undetectable ดังนั้นจึงสามารถแทนที่ด้วยสตริง" ไม่ได้กำหนด "สำหรับการเปรียบเทียบ

นี่เป็นปัญหาหนักอย่างหนึ่งในการปรับแต่งโค้ด: วิธีการรับประกันว่าโค้ดที่ได้รับการจัดเรียงใหม่เพื่อประสิทธิภาพจะยังคงมีผลเช่นเดียวกับต้นฉบับ


1

สิ่งนี้ได้รับการแก้ไขเมื่อสองเดือนก่อนและจะเข้าสู่ Chrome เร็ว ๆ นี้ (อยู่ใน Canary แล้ว)

V8 Issue 1912553002 - แก้ไข 'typeof null' canonicalization ในเพลาข้อเหวี่ยง

Chromium Issue 604033 - คอมไพเลอร์ JIT ไม่รักษาพฤติกรรมวิธีการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.