nodejs node example child_process child node.js event-handling child-process

node.js - node - npm install child_process



Diferencia entre ChildProcess close, exit eventos (3)

Cuando se spawn()/exec()/... procesos secundarios a través de spawn()/exec()/... en Node.js, hay un evento ''close'' y ''exit'' en los procesos secundarios.

¿Cuál es la diferencia entre esos dos y cuándo necesitas usar qué?


¿Miraste la documentación?

De acuerdo a this :

El evento de "cierre" se emite cuando se han cerrado las secuencias de stdio de un proceso hijo. Esto es distinto del evento ''exit'', ya que varios procesos pueden compartir las mismas secuencias de stdio .

El evento ''exit'' se emite después de que finaliza el proceso hijo. Si el proceso salió, el código es el código de salida final del proceso, de lo contrario, es nulo. Si el proceso finalizó debido a la recepción de una señal, la señal es el nombre de cadena de la señal, de lo contrario es nulo. Uno de los dos siempre será no nulo.


Antes de Node.js 0.7.7, solo había un evento de "salida" en procesos secundarios (y ningún evento de "cierre"). Este evento se activará cuando el proceso hijo haya salido y todas las transmisiones (stdin, stdout, stdout) se hayan cerrado.

En el Nodo 0.7.7 , se introdujo el evento "cerrar" ( ver confirmación ). La documentación (enlace permanente) actualmente dice:

El evento de "cierre" se emite cuando se han cerrado las secuencias de stdio de un proceso hijo. Esto es distinto del evento ''exit'', ya que varios procesos pueden compartir las mismas secuencias de stdio.

Si acaba de generar un programa y no hace nada especial con stdio, el evento "cerrar" se dispara después de "salir". El evento de "cierre" puede retrasarse si, por ejemplo, el flujo de salida estándar se canaliza a otro flujo. Esto significa que el evento "cerrado" puede retrasarse (indefinidamente) después del evento "salir".
¿Significa esto que el evento "cerrar" siempre se dispara después de "salir"? Como muestran los siguientes ejemplos, la respuesta es no.

Por lo tanto, si solo está interesado en la finalización del proceso (por ejemplo, porque el proceso tiene un recurso exclusivo), es suficiente con escuchar "salir". Si no le importa el programa, y ​​solo su entrada y / o salida, use el evento "cerrar".

Experimento: destruir stdio antes de matar a un niño.

Experimentalmente (en Node.js v7.2.0), encontré que si las secuencias de stdio no son utilizadas por el proceso hijo, entonces el evento "cerrar" solo se dispara después de que el programa haya salido:

// The "sleep" command takes no input and gives no output. cp = require(''child_process'').spawn(''sleep'', [''100'']); cp.on(''exit'', console.log.bind(console, ''exited'')); cp.on(''close'', console.log.bind(console, ''closed'')); cp.stdin.end(); cp.stdout.destroy(); cp.stderr.destroy(); console.log(''Closed all stdio''); setTimeout(function() { console.log(''Going to kill''); cp.kill(); }, 500);

El programa anterior genera salidas de "reposo":

Closed all stdio Going to kill exited null SIGTERM closed null SIGTERM

Cuando cambio las primeras líneas a un programa que solo da salida,

// The "yes" command continuously outputs lines with "y" cp = require(''child_process'').spawn(''yes'');

... entonces la salida es:

Closed all stdio exited 1 null closed 1 null Going to kill

Del mismo modo, cuando cambio engendro un programa que solo se lee desde stdin,

// Keeps reading from stdin. cp = require(''child_process'').spawn(''node'', [''-e'', ''process.stdin.resume()'']);

O cuando leo desde stdin y salida a stdout,

// "cat" without arguments reads from stdin, and outputs to stdout cp = require(''child_process'').spawn(''cat'');

Experimento: programa de tubería a otro, mata primero programa

El experimento anterior es bastante artificial. El siguiente experimento es un poco más realista: unes un programa a otro y matas al primero.

// Reads from stdin, output the input to stdout, repeat. cp = require(''child_process'').spawn(''bash'', [''-c'', ''while read x ; do echo "$x" ; done'']); cp.on(''exit'', console.log.bind(console, ''exited'')); cp.on(''close'', console.log.bind(console, ''closed'')); cpNext = require(''child_process'').spawn(''cat''); cp.stdout.pipe(cpNext.stdin); setTimeout(function() { // Let''s assume that it has started. Now kill it. cp.kill(); console.log(''Called kill()''); }, 500);

Salida:

Called kill() exited null SIGTERM closed null SIGTERM

De manera similar, cuando el primer programa solo lee de la entrada y nunca da salida

// Keeps reading from stdin, never outputs. cp = require(''child_process'').spawn(''bash'', [''-c'', ''while read ; do : ; done'']);

Cuando el primer programa sigue emitiendo sin esperar la entrada estándar, el comportamiento es diferente, como lo muestra el siguiente experimento.

Experimento: programa de tuberías con mucha salida a otra, mata el primer programa

// Equivalent to "yes | cat". cp = require(''child_process'').spawn(''yes''); cp.on(''exit'', console.log.bind(console, ''exited'')); cp.on(''close'', console.log.bind(console, ''closed'')); cpNext = require(''child_process'').spawn(''cat''); cp.stdout.pipe(cpNext.stdin); setTimeout(function() { // Let''s assume that it has started. Now kill it. cp.kill(); console.log(''Called kill()''); setTimeout(function() { console.log(''Expecting "exit" to have fired, and not "close"''); // cpNext.kill(); // ^ Triggers ''error'' event, errno ECONNRESET. // ^ and does not fire the ''close'' event! // cp.stdout.unpipe(cpNext.stdin); // ^ Does not appear to have any effect. // ^ calling cpNext.kill() throws ECONNRESET. // ^ and does not fire the ''close'' event! cp.stdout.destroy(); // <-- triggers ''close'' cpNext.stdin.destroy(); // ^ Without this, cpNext.kill() throws ECONNRESET. cpNext.kill(); }, 500); }, 500);

El programa anterior produce lo siguiente y luego sale:

Called kill() exited null SIGTERM Expecting "exit" to have fired, and not "close" closed null SIGTERM


la versión corta es, ''exit'' se emite cuando el hijo sale pero el stdio aún no está cerrado. ''close'' se emite cuando el niño ha salido y sus stdios están cerrados.

Además de eso comparten la misma firma.