node.js 的 console.log 是异步的吗?

Posted

技术标签:

【中文标题】node.js 的 console.log 是异步的吗?【英文标题】:is node.js' console.log asynchronous? 【发布时间】:2011-07-04 21:27:01 【问题描述】:

node.js 中的console.log/debug/warn/error 是异步的吗?我的意思是 javascript 代码执行会停止直到内容打印到屏幕上,还是会在稍后阶段打印?

另外,我有兴趣知道如果该语句在节点崩溃后立即显示,console.log 是否可能不显示任何内容。

【问题讨论】:

【参考方案1】:

更新:从 Node 0.6 开始,这篇文章已过时,因为 stdout 现在是同步了。

让我们看看console.log 究竟做了什么。

首先它是console module的一部分:

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

所以它只是做了一些格式化并写入process.stdout,到目前为止还没有异步。

process.stdout 是一个 getter defined on startup,它被延迟初始化,我添加了一些 cmets 来解释:

.... 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 的情况下,我们最终得到 here,这个东西继承自套接字。因此,该节点基本上所做的就是将数据推送到套接字,然后由终端处理其余的工作。

让我们测试一下吧!

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

终端打印出sockets内容大约需要1秒,而node只需要17毫秒将数据推送到终端。

流的情况也是如此,文件的情况也得到处理asynchronous。

所以是的 Node.js 忠实于它的非阻塞承诺。

【讨论】:

更新:node.js 中的标准输出现在是同步的:groups.google.com/group/nodejs/browse_thread/thread/… 我认为这已经过时了:github.com/nodejs/node/issues/3524#issuecomment-151097761 @IvoWetzel 我现在将不得不对此投反对票,因为它已经过时了。 我知道这已经过时了,但你在process.stdout.write() 之后立即说“到目前为止没有异步”,其中write() 定义为异步......【参考方案2】:

console.warn() 和 console.error() 被阻塞。在底层系统调用成功之前,它们不会返回。

是的,程序有可能在写入标准输出的所有内容都被刷新之前退出。 process.exit() 将立即终止节点,即使仍有排队写入标准输出。您应该使用 console.warn 来避免这种行为。

【讨论】:

这不适用于 Windows 中的 Node 0.10.25。 console.warn()console.error() 具有与 console.log() 相同的非阻塞行为。甚至还有package to solve the problem in Windows。【参考方案3】:

我的结论,在阅读 Node.js 10.* 文档(附在下面)之后。是您可以使用 console.log 进行日志记录, console.log 是同步的并在低级 c 中实现。 虽然 console.log 是同步的,但只有在您不记录大量数据时才会导致性能问题。

(下面的命令行示例演示,console.log async和console.error是sync

基于Node.js Doc's

当目标是终端或文件时,控制台函数是同步的(以避免在过早退出的情况下丢失消息),而当它是管道时是异步的(以避免长时间阻塞)。

也就是说,在下面的例子中,stdout 是非阻塞的,而 stderr 是阻塞的:

$ node script.js 2&gt; error.log | tee info.log

在日常使用中,除非您 > 记录大量数据,否则您无需担心阻塞/非阻塞二分法。

希望对你有帮助

【讨论】:

什么是“海量数据”?它是由对 console.log 的调用次数还是被写入的总量定义的?什么是巨大的 1KB/ms、1MB/ms、1GB/ms? 这样的东西是通过实验发现的 :) @MattG【参考方案4】:

Console.log 在 windows 中是异步的,而在 linux/mac 中是同步的。要使 console.log 在 Windows 中同步,请在您的开头写下这一行 代码可能在 index.js 文件中。此语句之后的任何 console.log 都将被解释器视为同步的。

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

【讨论】:

顺便说一句,Linux 不仅仅是 ubuntu。 谢谢,请原谅我的迂腐评论,但 Debian 是我的弱点,现在开始使用 Linux 的每个人似乎都认为 Ubuntu Linux(除了你,我知道你是不是其中之一)。祝你有美好的一天:)【参考方案5】:

您可以将其用于同步日志记录:

const fs = require('fs')
fs.writeSync(1, 'Sync logging\n')

【讨论】:

以上是关于node.js 的 console.log 是异步的吗?的主要内容,如果未能解决你的问题,请参考以下文章

node.js里的forEach也是异步的吗

node.js 异步系列函数的参数

node.js中的forEach是同步还是异步

同步和异步 以及node js 回调函数

node.js的异步I/O事件驱动单线程

node.js 如何决定一个语句是不是被异步处理?