console.log của node.js là không đồng bộ?


95

console.log/debug/warn/errortrong asynchrounous Node.js? Ý tôi là việc thực thi mã javascript sẽ tạm dừng cho đến khi nội dung được in trên màn hình hay nó sẽ in ở giai đoạn sau?

Ngoài ra, tôi quan tâm đến việc biết liệu console.log có thể KHÔNG hiển thị bất kỳ điều gì không nếu câu lệnh ngay sau khi nó gặp sự cố nút.

Câu trả lời:


102

Cập nhật: Bắt đầu với Node 0.6 bài đăng này đã lỗi thời, vì stdout hiện đang đồng bộ .

Hãy xem những gì console.logthực sự làm.

Trước hết, nó là một phần của mô-đun bảng điều khiển :

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

Vì vậy, nó chỉ đơn giản là thực hiện một số định dạng và ghi vào process.stdout, không có gì bất đồng bộ cho đến nay.

process.stdoutlà một getter được định nghĩa khi khởi động được khởi động một cách lười biếng, tôi đã thêm một số nhận xét để giải thích mọi thứ:

.... 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;
});

Trong trường hợp TTY và UNIX, chúng ta kết thúc ở đây , thứ này kế thừa từ socket. Vì vậy, tất cả những gì mà nút cơ bản làm là đẩy dữ liệu vào socket, sau đó thiết bị đầu cuối sẽ lo phần còn lại.

Hãy thử nghiệm nó!

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);

Kết quả

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

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

Thiết bị đầu cuối cần khoảng 1 giây để in ra nội dung ổ cắm, nhưng nút chỉ cần 17 mili giây để đẩy dữ liệu đến thiết bị đầu cuối.

Tương tự đối với trường hợp luồng và trường hợp tệp cũng được xử lý không đồng bộ .

Vì vậy, Node.js đúng với lời hứa không chặn của nó.


2
Cập nhật: stdout trong node.js hiện đã được đồng bộ: groups.google.com/group/nodejs/browse_thread/thread/…
dhruvbird

1
Tôi nghĩ rằng đây là lỗi thời bây giờ: github.com/nodejs/node/issues/3524#issuecomment-151097761
tforgione

@IvoWetzel Bây giờ tôi sẽ phải từ chối cái này vì nó đã lỗi thời.
Evan Carroll

Tôi biết đây là lỗi thời và tất cả mọi thứ, nhưng bạn nói “không có gì không đồng bộ cho đến nay” ngay sau process.stdout.write()đó write()là theo định nghĩa không đồng bộ ...
binki

26

console.warn () và console.error () đang chặn. Chúng không trở lại cho đến khi các lệnh gọi hệ thống cơ bản thành công.

Có, chương trình có thể thoát ra trước khi mọi thứ được ghi vào stdout được xóa. process.exit () sẽ kết thúc nút ngay lập tức, ngay cả khi vẫn còn hàng đợi ghi vào stdout. Bạn nên sử dụng console.warn để tránh hành vi này.


1
Điều này không đúng với Node 0.10.25 trong Windows. console.warn()console.error()có cùng hành vi không chặn của console.log(). Thậm chí còn có một gói để giải quyết vấn đề trong Windows .
Lucio Paiva

12

Kết luận của tôi, sau khi đọc tài liệu Node.js 10. * (Đính kèm bên dưới). là bạn có thể sử dụng console.log để ghi nhật ký, console.log là đồng bộ và được thực hiện ở mức thấp c. Mặc dù console.log là đồng bộ, nhưng nó sẽ không gây ra vấn đề về hiệu suất nếu bạn không ghi lại một lượng lớn dữ liệu.

(Ví dụ dòng lệnh bên dưới chứng minh, console.log async và console.error là sync )

Dựa trên Node.js Doc's

Các chức năng của bảng điều khiển là đồng bộ khi đích là một thiết bị đầu cuối hoặc một tệp (để tránh bị mất thông báo trong trường hợp thoát sớm) và không đồng bộ khi đó là một đường ống (để tránh bị chặn trong thời gian dài).

Đó là, trong ví dụ sau, stdout không bị chặn trong khi stderr đang chặn:

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

Trong việc sử dụng hàng ngày, sự phân đôi chặn / không chặn không phải là điều bạn nên lo lắng trừ khi bạn đăng nhập một lượng lớn dữ liệu.

Hy vọng nó giúp


"Một lượng lớn dữ liệu" là gì? Nó được xác định bằng số lần gọi đến console.log hay tổng số tiền được ghi? 1KB / ms lớn, 1MB / ms, 1GB / ms là gì?
MattG

3

Console.log không đồng bộ trong windows trong khi nó đồng bộ trong linux / mac. Để làm cho console.log đồng bộ trong windows, hãy viết dòng này ở đầu mã của bạn có thể là trong tệp index.js. Bất kỳ console.log nào sau câu lệnh này sẽ được trình thông dịch coi là đồng bộ.

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

Nhân tiện, Linux không chỉ là ubuntu.
ozanmuyes

Cảm ơn, thứ lỗi cho nhận xét lớn của tôi nhưng Debian là điểm yếu của tôi và có vẻ như mọi người bắt đầu sử dụng Linux ngày nay đều nghĩ Ubuntu Linux (ngoại trừ bạn, tôi biết rằng bạn không phải là một trong số họ). Chúc một ngày tốt lành :)
ozanmuyes 21/02/19
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.