Порождение нового процесса начинается немедленно (он передается ОС, чтобы фактически запустить процесс и запустить его). Запуск нового процесса с .spawn()
является асинхронным и неблокирующим. Итак, он начнет работу с ОС и сразу же вернется. Вы можете подумать, что именно поэтому все в порядке, чтобы установить обработчики событий после его возвращения (потому что процесс еще не закончил запуск). Ну да и нет. Вероятно, он еще не закончил запуск нового процесса, но это не главная причина, по которой все в порядке.
Все нормально, потому что node.js пропускает все свои события через одну многопоточную очередь событий. Таким образом, никакие события из недавно созданного процесса не могут быть обработаны, пока ваш код не завершит выполнение и не вернет управление обратно в систему. Только тогда он сможет обработать следующее событие в очереди событий и вызвать одно из событий, для которых вы регистрируете обработчики.
Или, иначе говоря, ни одно из событий другого процесса не имеет преимущественного значения. Они не будут / не могут прервать ваш существующий код Javascript. Итак, поскольку вы все еще запускаете свой код Javascript, эти события еще не могут быть запущены. Вместо этого они сидят в очереди событий до тех пор, пока ваш код Javascript не завершится, и тогда интерпретатор может go получить следующее событие из очереди событий и запустить связанный с ним обратный вызов. Аналогично, этот обратный вызов выполняется до тех пор, пока он не возвращается обратно к интерпретатору, а затем интерпретатор может получить следующее событие и выполнить свой обратный вызов и т. Д. ...
Именно поэтому node.js называется системой, управляемой событиями.
Таким образом, совершенно нормально делать такой тип структуры:
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
Ни одно из этих событий data
или close
не может выполнять свои обратные вызовы до тех пор, пока ваш код не будет выполнен и возвращает управление обратно в систему. Таким образом, совершенно безопасно настроить такие обработчики событий, как вы. Даже если недавно созданный процесс был запущен и сразу генерировал события, эти события будут просто находиться в очереди событий, пока ваш Javascript не завершит свою работу (включая настройку обработчиков событий).
Теперь , если вы отложили настройку обработчиков событий до некоторого будущего тика события l oop (как показано ниже) с чем-то вроде setTimeout()
, то вы можете пропустить некоторые события:
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
setTimeout(() => {
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
}, 10);
Здесь вы устанавливаете обработчики событий не сразу, как часть одного и того же тика события l oop, но после небольшой задержки. Поэтому некоторые события могут быть обработаны из события l oop перед установкой обработчиков событий, и вы можете пропустить некоторые из этих событий. Очевидно, что вы никогда бы не сделали это таким образом (намеренно), но я просто хотел показать, что код, работающий на одном и том же тике события l oop, не имеет проблем, но код, запущенный на некотором будущем тике события У l oop может быть проблема с пропущенными событиями.