#node.js #subprocess #ipc
Вопрос:
У меня есть функция, которая асинхронно порождает дочерний процесс, чтобы я мог прослушивать ошибки дочернего процесса, например:
function runCmd(cmd, args, cwd) {
let childProc = childProcess.spawn(cmd, args, {
encoding: 'utf8',
cwd: cwd,
stdio: ['ignore', 'pipe', 'pipe']
});
childProc.on('error', (err) => {
console.error(`backend error: ${err}`);
})
childProc.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
childProc.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
childProc.on('close', (code) => {
console.log(`child process closed with code ${code}`);
});
childProc.on('exit', () => {
console.log(`child process is gone`);
});
}
Наблюдение против Ожидание
Однако эта функция немедленно завершается, в то время как я хочу, чтобы она блокировалась до тех пор, пока я не найду способ выйти в одном из прослушивателей событий.
Я пробовал различные способы, такие как использование цикла while(true) (он блокирует все, включая дочерний процесс, потому что NodeJS однопоточный), или обещание, такое как
await new Promise( (resolve) => {
child.on('close', resolve)
})
Обходные пути
Я мог бы использовать spawnSync
, но он зависает, если происходит сбой дочернего процесса, без каких-либо ошибок на этом пути.
Самое забавное, что если я помещу spawnSync
его в блок try-catch, я все равно ничего не получу в блоке catch, что означает spawnSync()
, что вызов просто зависает.
Мне было удобно работать с модулем подпроцесса Python, где родительский процесс всегда получает информацию обратно при сбое синхронно созданного дочернего процесса.
Поэтому способ Нодейса справиться с этим, то есть просто зависнуть навсегда, мне кажется немного странным.
Вопросы
Как я мог бы получить лучшее из обоих миров spawn
и spawnSync
? т. Е.,
- Заблокируйте функцию до тех пор, пока дочерний процесс не завершится или не завершится сбоем
- Получите всю информацию о stdout/stderr из дочернего процесса, несмотря ни на что
Комментарии:
1. Как вы сказали,
spawn
является асинхронной, функцияrunCmd
возвращается, не дожидаясь завершения вашего дочернего процесса, поэтому она всегда завершается немедленно. И если вы используетеspawnSync
, вам нужно поместитьspawnSync
вtry-catch
блок, тогда вы можете поймать ошибки.2. @lx1412 Самое смешное, что он на самом деле никогда не доходит до моего блока catch. Он просто зависает на spawnSync.
3. Это не сработает так, как вы хотите, и попытка втиснуть это в вашу уже существующую ментальную модель не закончится хорошо. Блокировка основного потока дочернего процесса обычно не является хорошей идеей ни на одном языке. Самое близкое, к чему вы можете подойти, — это чтобы ваша функция возвращала обещание, которое разрешается в обработчике выхода вашего ребенка. Вы можете
await
это сделать в вызывающем абоненте.