console.log ของ node.js เป็นแบบอะซิงโครนัสหรือไม่


95

อยู่console.log/debug/warn/errorใน asynchrounous Node.js? ฉันหมายความว่าจะหยุดการเรียกใช้โค้ดจาวาสคริปต์จนกว่าสิ่งต่างๆจะถูกพิมพ์บนหน้าจอหรือจะพิมพ์ในภายหลัง?

นอกจากนี้ฉันสนใจที่จะทราบว่าเป็นไปได้หรือไม่ที่ console.log จะไม่แสดงอะไรเลยหากคำสั่งนั้นเกิดปัญหาขึ้นทันทีหลังจากที่โหนดขัดข้อง

คำตอบ:


103

อัปเดต:เริ่มต้นด้วยโหนด 0.6 โพสต์นี้ล้าสมัยเนื่องจาก stdout เป็นแบบซิงโครนัสในขณะนี้

เรามาดูกันดีกว่าว่ามีอะไรconsole.logบ้าง

ก่อนอื่นมันเป็นส่วนหนึ่งของโมดูลคอนโซล :

exports.log = function() {
  process.stdout.write(format.apply(this, arguments) + '\n');
};

ดังนั้นมันจึงทำการจัดรูปแบบและเขียนข้อมูลบางอย่างprocess.stdoutโดยไม่มีอะไรที่ไม่ตรงกัน

process.stdoutเป็น getter ที่กำหนดไว้ในการเริ่มต้นซึ่งเริ่มต้นอย่างเฉื่อยชาฉันได้เพิ่มความคิดเห็นเพื่ออธิบายสิ่งต่างๆ:

.... code here...
process.__defineGetter__('stdout', function() {
  if (stdout) return stdout;                            // only initialize it once 

  /// many requires here ...

  if (binding.isatty(fd)) {                             // a terminal? great!
    stdout = new tty.WriteStream(fd);
  } else if (binding.isStdoutBlocking()) {              // a file?
    stdout = new fs.WriteStream(null, {fd: fd});
  } else {
    stdout = new net.Stream(fd);                        // a stream? 
                                                        // For example: node foo.js > out.txt
    stdout.readable = false;
  }

  return stdout;
});

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

มาทดสอบกัน!

var data = '111111111111111111111111111111111111111111111111111';
for(var i = 0, l = 12; i < l; i++) {
    data += data; // warning! gets very large, very quick
}

var start = Date.now();
console.log(data);
console.log('wrote %d bytes in %dms', data.length, Date.now() - start);

ผลลัพธ์

....a lot of ones....1111111111111111
wrote 208896 bytes in 17ms

real    0m0.969s
user    0m0.068s
sys  0m0.012s

เทอร์มินัลใช้เวลาประมาณ 1 วินาทีในการพิมพ์เนื้อหาซ็อกเก็ต แต่โหนดต้องการเพียง 17 มิลลิวินาทีในการพุชข้อมูลไปยังเทอร์มินัล

เดียวกันจะไปสำหรับกรณีกระแสและยังมีกรณีไฟล์ที่ได้รับการจัดการไม่ตรงกัน

ดังนั้นใช่ Node.js ถือเป็นจริงสัญญาไม่ปิดกั้นของมัน


2
อัปเดต: stdout ใน node.js เป็นแบบซิงโครนัสแล้ว: groups.google.com/group/nodejs/browse_thread/thread/…
dhruvbird

1
ฉันคิดว่าสิ่งนี้ล้าสมัยแล้ว: github.com/nodejs/node/issues/3524#issuecomment-151097761
tforgione

@IvoWetzel ฉันจะต้องลงคะแนนตอนนี้เพราะมันล้าสมัย
Evan Carroll

ฉันรู้ว่าสิ่งนี้ล้าสมัยและทุกอย่าง แต่คุณพูดว่า“ ไม่มีอะไรอะซิงโครนัสจนถึงตอนนี้” ทันทีหลังจากprocess.stdout.write()ที่write()คำจำกัดความอะซิงโครนัส…
binki

27

console.warn () และ console.error () กำลังบล็อก พวกเขาจะไม่กลับมาจนกว่าการเรียกระบบพื้นฐานจะสำเร็จ

ใช่มันเป็นไปได้ที่โปรแกรมจะออกก่อนที่ทุกอย่างที่เขียนถึง stdout จะถูกล้าง process.exit () จะยุติโหนดทันทีแม้ว่าจะยังคงมีการเขียนคิวไว้ใน stdout คุณควรใช้ console.warn เพื่อหลีกเลี่ยงพฤติกรรมนี้


1
สิ่งนี้ไม่เป็นความจริงสำหรับ Node 0.10.25 ใน Windows console.warn()และมีพฤติกรรมที่ไม่ปิดกั้นเดียวกันของconsole.error() console.log()มีแม้กระทั่งแพคเกจในการแก้ปัญหาใน Windows
Lucio Paiva

12

ข้อสรุปของฉันหลังจากอ่าน Node.js 10. * docs (แนบด้านล่าง) คือคุณสามารถใช้ console.log สำหรับการบันทึกได้console.logจะซิงโครนัสและใช้งานในระดับต่ำ c แม้ว่า console.log จะซิงโครนิก แต่จะไม่ทำให้เกิดปัญหาด้านประสิทธิภาพหากคุณไม่ได้บันทึกข้อมูลจำนวนมาก

(ตัวอย่างบรรทัดคำสั่งด้านล่างสาธิต console.log asyncและ console.error คือการซิงค์ )

ขึ้นอยู่กับNode.js Doc's

ฟังก์ชันคอนโซลจะซิงโครนัสเมื่อปลายทางคือเทอร์มินัลหรือไฟล์ (เพื่อหลีกเลี่ยงข้อความที่สูญหายในกรณีที่ออกก่อนเวลาอันควร) และแบบอะซิงโครนัสเมื่อเป็นไปป์ (เพื่อหลีกเลี่ยงการปิดกั้นเป็นเวลานาน)

นั่นคือในตัวอย่างต่อไปนี้ stdout ไม่ปิดกั้นในขณะที่ stderr กำลังบล็อก:

$ node script.js 2> error.log | tee info.log

ในการใช้งานประจำวันการแบ่งขั้วแบบบล็อก / ไม่ปิดกั้นไม่ใช่สิ่งที่คุณควรกังวลเว้นแต่คุณจะ> บันทึกข้อมูลจำนวนมาก

หวังว่าจะช่วยได้


"ข้อมูลจำนวนมหาศาล" คืออะไร? ถูกกำหนดโดยจำนวนการโทรไปที่ console.log หรือจำนวนเงินทั้งหมดที่เขียน? ขนาดใหญ่ 1KB / ms, 1MB / ms, 1GB / ms คืออะไร?
MattG

3

Console.log เป็นแบบอะซิงโครนัสใน windows ในขณะที่ซิงโครนัสใน linux / mac ในการทำให้ console.log ซิงโครไนซ์ใน windows ให้เขียนบรรทัดนี้ที่จุดเริ่มต้นของโค้ดของคุณซึ่งอาจอยู่ในไฟล์ index.js console.log ใด ๆ หลังจากคำสั่งนี้จะถือว่าเป็นแบบซิงโครนัสโดยล่าม

if (process.stdout._handle) process.stdout._handle.setBlocking(true);

Linux ไม่ใช่แค่ ubuntu เท่านั้น
ozanmuyes

ขอบคุณขอโทษความคิดเห็นที่อวดดีของฉัน แต่ Debian เป็นจุดอ่อนของฉันและดูเหมือนว่าทุกคนที่เริ่มใช้ Linux ในปัจจุบันคิดว่า Ubuntu คือ Linux (ยกเว้นคุณฉันรู้ว่าคุณไม่ใช่หนึ่งในนั้น) ขอให้มีความสุขมาก ๆ นะครับ :)
ozanmuyes
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.