console.log () async หรือ sync?


93

ฉันกำลังอ่านAsync Javascriptโดย Trevor Burnham นี่เป็นหนังสือที่ยอดเยี่ยมมาก

เขาพูดถึงตัวอย่างนี้และ console.log ว่าเป็น "async" ในคอนโซล Safari และ Chrome น่าเสียดายที่ฉันไม่สามารถจำลองสิ่งนี้ได้ นี่คือรหัส:

var obj = {}; 
console.log(obj); 
obj.foo = 'bar';
// my outcome: Object{}; 'bar';
// The book outcome: {foo:bar};

ถ้านี่คือ async ฉันจะคาดหวังว่าผลลัพธ์จะเป็นหนังสือ console.log () ใส่ไว้ในคิวเหตุการณ์จนกว่าโค้ดทั้งหมดจะถูกเรียกใช้งานจากนั้นรันและจะมีคุณสมบัติ bar

ดูเหมือนว่าจะทำงานพร้อมกัน

ฉันใช้รหัสนี้ผิดหรือไม่? console.log เป็น async จริงหรือ?


@thefourtheye: ไม่ดังนั้นฉันควรจะลบความคิดเห็นของฉัน
คุกกี้มอนสเตอร์

1
ฉันเคยเห็นมันเกิดขึ้นใน Chrome หากคุณ console.log ออบเจ็กต์ธรรมดาแล้วเปลี่ยนบางสิ่งในออบเจ็กต์ทันทีสิ่งนั้นconsole.log()จะไม่แสดงค่าเดิมเสมอไป วิธีหลีกเลี่ยงหากสิ่งนี้เกิดขึ้นกับคุณคือการแปลงสิ่งที่คุณพยายามconsole.log()จะเป็นสตริงที่ไม่เปลี่ยนรูปเพื่อไม่ให้เกิดปัญหานี้ ดังนั้นจากประสบการณ์console.log()มีปัญหา async ที่อาจเกี่ยวข้องกับการจัดเก็บข้อมูลข้ามขอบเขตของกระบวนการ นี่ไม่ใช่พฤติกรรมที่ตั้งใจไว้ แต่เป็นผลข้างเคียงบางประการของการconsole.log()ทำงานภายใน (โดยส่วนตัวแล้วฉันคิดว่ามันเป็นข้อบกพร่อง)
jfriend00


1
@bergi ฉันใช้เวลาเพียง 10 นาทีในการค้นหาคนหลอกลวงนี้ (แม้ว่าฉันจะรู้ชื่อที่แน่นอน) อาจเป็นเพราะมันถูกปิด เราไม่สามารถสลับรายการที่ซ้ำกันได้หรือไม่เพื่อให้อีกรายการหนึ่งเป็นผู้หลอกลวง ... ?
Jonas Wilms

1
@JonasWilms ตอนนี้ฉันได้เปิดคำถามนี้อีกครั้งแล้ว (ดูประวัติ ) ฉันไม่คิดว่ามันซ้ำกันฉันใช้คอนโซล JavaScript ของ Chrome ขี้เกียจในการประเมินอาร์เรย์หรือไม่? เป็นเป้าหมายมาตรฐานสำหรับปัญหาที่เกี่ยวข้องกับอาร์เรย์โดยเฉพาะ
Bergi

คำตอบ:


114

console.logไม่ได้เป็นมาตรฐานดังนั้นพฤติกรรมจึงค่อนข้างไม่มีการกำหนดและสามารถเปลี่ยนแปลงได้อย่างง่ายดายจากรุ่นสู่รุ่นของเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ หนังสือของคุณมีแนวโน้มที่จะล้าสมัยเนื่องจากคำตอบของฉันในไม่ช้า

สำหรับรหัสของเรามันไม่ได้สร้างความแตกต่างใด ๆ ไม่ว่าจะconsole.logเป็นแบบ async หรือไม่ก็ไม่มีการโทรกลับใด ๆ และค่าที่คุณส่งผ่านจะถูกอ้างอิงและคำนวณเสมอเมื่อคุณเรียกใช้ฟังก์ชัน

เราไม่รู้จริงๆว่าจะเกิดอะไรขึ้น (ตกลงเราทำได้เนื่องจาก Firebug, Chrome Devtools และ Opera Dragonfly เป็นโอเพ่นซอร์สทั้งหมด) คอนโซลจะต้องจัดเก็บค่าที่บันทึกไว้ที่ใดที่หนึ่งและจะแสดงบนหน้าจอ การแสดงผลจะเกิดขึ้นแบบอะซิงโครนัสอย่างแน่นอน (ถูกควบคุมให้เป็นการอัปเดต จำกัด อัตรา) เช่นเดียวกับการโต้ตอบในอนาคตกับอ็อบเจ็กต์ที่บันทึกในคอนโซล (เช่นการขยายคุณสมบัติอ็อบเจ็กต์)

ดังนั้นคอนโซลอาจโคลน (ทำให้เป็นอนุกรม) อ็อบเจ็กต์ที่ไม่แน่นอนที่คุณบันทึกไว้หรือจะเก็บข้อมูลอ้างอิงไว้ อันแรกใช้ไม่ได้ผลกับวัตถุที่ลึก / ใหญ่ นอกจากนี้อย่างน้อยการแสดงผลครั้งแรกในคอนโซลอาจจะแสดงสถานะ "ปัจจุบัน" ของวัตถุหนึ่งคือเมื่อมันได้รับการบันทึกไว้ - Object {}ในตัวอย่างของคุณที่คุณเห็น

อย่างไรก็ตามเมื่อคุณขยายออบเจ็กต์เพื่อตรวจสอบคุณสมบัติเพิ่มเติมเป็นไปได้ว่าคอนโซลจะจัดเก็บเฉพาะการอ้างอิงไปยังออบเจ็กต์และคุณสมบัติของคุณและการแสดงตอนนี้จะแสดงสถานะปัจจุบัน (กลายพันธุ์แล้ว) หากคุณคลิกที่+คุณควรจะเห็นbarคุณสมบัติในตัวอย่างของคุณ

นี่คือภาพหน้าจอที่โพสต์ในรายงานข้อบกพร่องเพื่ออธิบาย "การแก้ไข":

ดังนั้นค่าบางค่าอาจถูกอ้างอิงนานหลังจากที่บันทึกไว้และการประเมินค่าเหล่านี้ค่อนข้างขี้เกียจ ("เมื่อจำเป็น") ตัวอย่างที่มีชื่อเสียงที่สุดของความคลาดเคลื่อนนี้ได้รับการจัดการในคำถามคอนโซล JavaScript ของ Chrome ขี้เกียจเกี่ยวกับการประเมินอาร์เรย์หรือไม่?

console.log(JSON.stringify(obj))การแก้ปัญหาเพื่อให้แน่ใจว่าการเข้าสู่ระบบภาพรวมต่อเนื่องของวัตถุของคุณเสมอเช่นโดยการทำ วิธีนี้ใช้ได้กับวัตถุที่ไม่เป็นวงกลมและค่อนข้างเล็กเท่านั้น ดูเพิ่มเติมฉันจะเปลี่ยนพฤติกรรมเริ่มต้นของ console.log ใน Safari ได้อย่างไร .

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


2
ฉันมีปัญหาเดียวกันกับ console.log ที่ไม่เป็น async ใช้ JSON.stringify แก้ไขให้ฉัน
russiansummer

ในปี 2019 เราสามารถพูดได้ว่าconsole.logยังคงเป็นแบบอะซิงโครนัสใน Chrome เหมือนอายุ 8 ปี (ดูstackoverflow.com/questions/7389069/… ) สิ่งเดียวที่เปลี่ยนแปลงคือตอนนี้ Chrome แสดงภาพรวมของวัตถุอ้างอิงที่ เวลาที่คุณโทรconsole.log(ถ้าคุณขยายอ็อบเจ็กต์ที่บันทึกไว้คุณจะเห็นคุณสมบัติและค่าสุดท้ายของมันหลังจากการดำเนินการกลายพันธุ์ที่คุณทำหลังจากนั้นconsole.log) หรือเป็นconsole.logซิงโครนัส?
tonix

@tonix ใช่พฤติกรรมนี้ไม่น่าจะเปลี่ยนแปลงได้เนื่องจากเหตุผลที่ระบุไว้ในคำตอบของฉัน ไม่ใช่ข้อบกพร่อง แต่เป็นเพียงวิธีการทำงานของดีบักเกอร์ / ตัวตรวจสอบแบบโต้ตอบ
Bergi

หากคุณใช้JSON.parse(JSON.stringify(obj))ตามที่ระบุไว้ในความคิดเห็นที่นี่คุณจะได้รับ snapshot ในรูปแบบวัตถุแทนที่จะเป็นสตริง
ร่วง

TL; DR. way way way TL
Rick O'Shea

2

นี่ไม่ใช่คำตอบสำหรับคำถาม แต่อาจเป็นประโยชน์สำหรับคนที่สะดุดในโพสต์นี้และยาวเกินไปที่จะแสดงความคิดเห็น:

window.console.logSync = (...args) => {
  try {
    args = args.map((arg) => JSON.parse(JSON.stringify(arg)));
    console.log(...args);
  } catch (error) {
    console.log('Error trying to console.logSync()', ...args);
  }
};

สิ่งนี้จะสร้างเวอร์ชันหลอกซิงโครนัconsole.logส แต่มีข้อแม้เดียวกันกับที่กล่าวไว้ในคำตอบที่ยอมรับ

เนื่องจากในขณะนี้เบราว์เซอร์ส่วนใหญ่console.logเป็นแบบอะซิงโครนัสในบางลักษณะคุณอาจต้องการใช้ฟังก์ชันเช่นนี้ในบางสถานการณ์


0

เมื่อใช้ console.log:

a = {}; a.a=1;console.log(a);a.b=function(){};
// without b
a = {}; a.a=1;a.a1=1;a.a2=1;a.a3=1;a.a4=1;a.a5=1;a.a6=1;a.a7=1;a.a8=1;console.log(a);a.b=function(){};
// with b, maybe
a = {}; a.a=function(){};console.log(a);a.b=function(){};
// with b

ในสถานการณ์แรกออบเจ็กต์นั้นง่ายพอดังนั้นคอนโซลจึงสามารถ "สตริง" ให้กับคุณได้ แต่ในสถานการณ์อื่น ๆ a นั้น 'ซับซ้อนเกินไป' ถึง 'stringify' ดังนั้นคอนโซลจะแสดงวัตถุในหน่วยความจำให้คุณแทนและใช่เมื่อคุณดูที่ b ได้แนบกับไฟล์.


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