o console.log do node.js é assíncrono?

95

Estão console.log/debug/warn/error node.js é assíncrono? Quero dizer, a execução do código javascript será interrompida até que o material seja impresso na tela ou será impresso em um estágio posterior?

Além disso, estou interessado em saber se é possível que um console.log NÃO exiba nada se a instrução imediatamente após travar o nó.

Dhruvbird
fonte

Respostas:

102

Atualização: a partir do Node 0.6, este post está obsoleto, já que stdout é síncrono agora.

Bem, vamos ver o que console.logrealmente faz.

Em primeiro lugar, faz parte do módulo do console :

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

Portanto, ele simplesmente formata e grava process.stdout, nada de forma assíncrona até agora.

process.stdouté um getter definido na inicialização que é inicializado lentamente, adicionei alguns comentários para explicar as coisas:

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

No caso de um TTY e UNIX a gente acaba aqui , essa coisa herda do socket. Portanto, tudo o que o nó faz basicamente é enviar os dados para o soquete, e o terminal cuida do resto.

Vamos testar!

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

Resultado

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

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

O terminal precisa de cerca de 1 segundo para imprimir o conteúdo dos sockets, mas o nó só precisa de 17 milissegundos para enviar os dados para o terminal.

O mesmo vale para o caso de fluxo e também o caso de arquivo é tratado de forma assíncrona .

Então, sim, o Node.js se mantém fiel às suas promessas de não bloqueio.

Ivo Wetzel
fonte
2
Atualização: stdout em node.js agora é síncrono: groups.google.com/group/nodejs/browse_thread/thread/…
dhruvbird
1
Acho que isso está obsoleto agora: github.com/nodejs/node/issues/3524#issuecomment-151097761
tforgione
@IvoWetzel Vou ter que votar contra isso agora, pois é obsoleto.
Evan Carroll
Eu sei que isso é obsoleto e tudo mais, mas você diz "nada assíncrono até agora" imediatamente depois, process.stdout.write()onde write()está, por definição, assíncrono ...
binki
26

console.warn () e console.error () estão bloqueando. Eles não retornam até que as chamadas de sistema subjacentes sejam bem-sucedidas.

Sim, é possível que um programa saia antes que tudo escrito em stdout seja liberado. process.exit () encerrará o nó imediatamente, mesmo se ainda houver gravações enfileiradas no stdout. Você deve usar console.warn para evitar esse comportamento.

Matt Ranney
fonte
1
Isso não é verdade para o Nó 0.10.25 no Windows. console.warn()e console.error()têm o mesmo comportamento sem bloqueio de console.log(). Existe até um pacote para resolver o problema no Windows .
Lucio Paiva
12

Minha conclusão, depois de ler Node.js 10. * docs (anexo abaixo). é que você pode usar console.log para registro, console.log é síncrono e implementado em baixo nível c. Embora o console.log seja sincronizado, ele não causará problemas de desempenho apenas se você não registrar uma grande quantidade de dados.

(O exemplo de linha de comando abaixo demonstra, console.log async e console.error é sync )

Baseado em Node.js Doc's

As funções do console são síncronas quando o destino é um terminal ou arquivo (para evitar perda de mensagens em caso de saída prematura) e assíncronas quando é um pipe (para evitar o bloqueio por longos períodos).

Ou seja, no exemplo a seguir, stdout não bloqueia enquanto stderr está bloqueando:

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

No uso diário, a dicotomia bloqueio / não bloqueio não é algo com que você deva se preocupar, a menos que registre grandes quantidades de dados.

Espero que ajude

Doron Aviguy
fonte
O que é uma "grande quantidade de dados"? É definido pelo número de chamadas para console.log ou pelo valor total sendo gravado? O que é um enorme 1 KB / ms, 1 MB / ms, 1 GB / ms?
MattG
3

Console.log é assíncrono no Windows enquanto é síncrono no linux / mac. Para tornar o console.log síncrono no Windows, escreva esta linha no início do seu código, provavelmente no arquivo index.js. Qualquer console.log após esta instrução será considerado síncrono pelo interpretador.

if (process.stdout._handle) process.stdout._handle.setBlocking(true);
Ali Azlan
fonte
O Linux não é apenas ubuntu, a propósito.
ozanmuyes
Obrigado, desculpe meu comentário pedante, mas Debian é meu ponto fraco e parece que todos que começaram a usar Linux hoje em dia pensam que Ubuntu é Linux (exceto você, eu sei que você não é um deles). Tenha um bom dia :)
ozanmuyes