#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…