Как правильно использовать node.js перенаправление child_process.spawn() в Windows?

#node.js

#node.js

Вопрос:

У меня есть чистое окно Windows 8.1 с последними node.js установлен (версия 0.10.29). У меня есть следующий тестовый код в двух файлах:

a.js

 var sub = require('child_process').spawn('node', ['b.js'], {silent: true});
sub.stdout.on("data", function (data) {console.log(data.toString());});
  

b.js

 console.log("DEBUG 1");
console.log("DEBUG 2");
process.exit();
  

если я выполняю a.ja через:

 node a.js
  

Я увижу «DEBUG 1» в выводе консоли, но не «DEBUG 2». Если я удалю process.exit() , обе строки будут отображаться правильно. Это странное поведение происходит как с fork и spawn .

Какие-либо подсказки? Тот же код работает без проблем в Linux.

Обновление 02.07.2014

Кажется, это не условие гонки между exit() и log(), поскольку изменение этого значения на чистую последовательность приводит к той же ошибке:

 function print(text, next) { console.log(text); next(); }
print("DEBUG 1", function () {
  print("DEBUG 2", function () {
    process.exit();
  });
});
  

Обновление 03.07.2014

silent не указан в spawn() документации, но он работает. Это указано в fork документации, и, как я уже упоминал ранее, эта проблема аналогична fork .

Кажется, что если я введу задержку между последним выводом, и process.exit() все будет работать правильно:

 console.log("DEBUG 1");
console.log("DEBUG 2");
setTimeout(function () {process.exit();}, 10000);
  

Но проблема проявляется только в том случае, если я передаю вывод в родительский процесс: если я удаляю silent , оба сообщения отображаются корректно даже без задержек, так что, скорее всего, что-то не так с каналом связи, а не с process.exit .

Больше обновлений 03.07.2014

В комментариях было высказано предположение, что это process.exit() может привести к завершению обоих процессов (как a.ja и b.ja ). Нет, он завершает только порожденный / разветвленный процесс, я проверил это, добавив infinite setTimeout to a.js , он успешно работает после b.ja завершения, и по-прежнему нет строки «DEBUG 2».

Комментарии:

1. Я думаю, это потому, что node.js является асинхронным, и process.exit выполняется перед консолью. конец журнала. Что, если вы попытаетесь выполнить обратный вызов? function print(text, callback) {console.log(text); callback();} print("DEBUG1", function () {print("DEBUG2", function () {process.exit();})});

2. @DrakaSAN Обновленный вопрос, та же проблема.

3. Кроме того, опция отключения звука не упоминается в документации spawn.

4. @DrakaSAN Спасибо, что указали на это. Обновленный вопрос о spawn и fork

5. есть ли что-нибудь еще, чтобы ответить с момента моего последнего редактирования? Итак, я могу переписать свой ответ, чтобы сделать его более понятным?

Ответ №1:

Основное редактирование для ясности:

Проблема, с которой вы сталкиваетесь, заключается в одновременном событии между console.log('DEBUG2') и process.end() , два из них вызываются (почти) одновременно, но process.end() имеют более высокий приоритет, и когда это будет сделано, sub остановите прослушивание события и, таким образом, остановите печать DEBUG2:

В вашем коде:

 a.js                |b.js
start
spawn               |start
listen              |send('DEBUG1')
get DEBUG1          |send('DEBUG2')
start the event     |send KILL
print DEBUG1        |
get DEBUG2
start the event
get KILL
kill b.js //DEBUG2 haven t been printed
  

Теперь, если вы замедляете process.end:

b.js:

 console.log('DEBUG1');
console.log('DEBUG2');
setTimeout(function () {
    process.end();
}, 1000);

a.js                |b.js
start
spawn               |start
listen              |send('DEBUG1')
get DEBUG1          |send('DEBUG2')
start the event     |wait
print DEBUG1        |wait
get DEBUG2          |send KILL
start the event
print DEBUG2
get KILL
kill b.js
  

Но это надоедливо, и вы не можете знать, сколько будет «ждать». Другое решение — заставить b.js наследовать стандартный вывод, чтобы не было события для создания:

a.js:

 var sub = require('child_process').spawn('node', ['b.js'], {stdio:[process.stdin, process.stdout, process.stderr]});

a.js                |b.js
start
spawn               |start
listen              |print DEBUG1
                    |print DEBUG2
                    |send KILL
get KILL            |
kill b.js
  

Теперь нет кода, подверженного ошибкам, но вы не можете получить то, что напечатано в .js. Я думаю, что другое решение с process.nextTick может сработать, но я не знаю, как это будет работать.

Редактировать:

process.exit() убейте b.js, что является предполагаемым поведением. a.js видит завершение data события, и поэтому имеет пустой цикл событий, и поэтому убивает себя 🙂

Комментарии:

1. Обновленный вопрос, спасибо за исследование. Я приму ваш ответ, если никто не объяснит, в чем проблема с pipe и process.exit()

2. Добавлено некоторое объяснение проблемы.

3. Это невозможно для process.exit(), чтобы завершить всю программу. «spawn» и «fork» запускают отдельный процесс. Проблема остается, даже если я помещаю и бесконечный цикл в .js (он никогда не заканчивается). Таким образом, «process.exit()» фактически завершает только b.js :(. Обновленный вопрос.

4. Слушая sub.end, я вижу, что вы так же правы, как и я. process.exit только убивает b.js, но каким-то образом отменяет событие data…