Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Дочерние процессы

Дочерний процесс — другая программа, которую запускает ваша: git, архиватор, конвертер картинок или ещё один скрипт на Node.js. Модуль node:child_process позволяет запустить её, передать аргументы и получить результат. Это нужно, когда готовая утилита уже умеет то, что вам требуется.

execFile: получить результат

execFile() запускает программу, ждёт её завершения и отдаёт весь вывод. В связке с promisify() из node:util её можно ждать через await:

import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
 
const run = promisify(execFile);
 
const { stdout } = await run(process.execPath, ['--version']);
 
console.log(`Версия Node.js: ${stdout.trim()}`);

process.execPath — полный путь к программе node. Пример запускает её с флагом --version и выводит, например, «Версия Node.js: v22.12.0». stdout — то, что программа напечатала.

Запуск своего скрипта

Тем же способом запускают другой скрипт и передают ему аргументы:

import { execFile } from 'node:child_process';
import { writeFile } from 'node:fs/promises';
import { promisify } from 'node:util';
 
const run = promisify(execFile);
 
await writeFile('count.mjs', 'console.log(process.argv.slice(2).length);');
const { stdout } = await run(process.execPath, ['count.mjs', 'a', 'b', 'c']);
 
console.log(`Аргументов: ${stdout.trim()}`); // Аргументов: 3

Пример сначала создаёт маленький скрипт count.mjs, затем запускает его как отдельную программу.

Ошибка в дочернем процессе

Если программа завершилась с кодом не 0, промис отклоняется. В ошибке есть код завершения и всё, что программа вывела:

import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
 
const run = promisify(execFile);
 
try {
  await run(process.execPath, ['-e', 'process.exit(3)']);
} catch (error) {
  console.log(`Программа завершилась с кодом ${error.code}`); // 3
}

spawn: долгие команды

spawn() не копит вывод, а передаёт его по мере появления. Параметр stdio: 'inherit' выводит всё прямо в ваш терминал — удобно для сборки или установки пакетов:

// scripts/backup.js
import { spawn } from 'node:child_process';
 
const child = spawn('git', ['log', '--oneline', '-5'], { stdio: 'inherit' });
 
child.on('close', (code) => {
  console.log(`git завершился с кодом ${code}`);
});

node scripts/backup.js покажет пять последних коммитов проекта, а затем код завершения.

ФункцияКогда использовать
execFile()Короткий вывод, нужен целиком
spawn()Долгая работа, большой вывод
exec()Нужна строка оболочки с && или перенаправлением

Частая ошибка

exec() выполняет строку через командную оболочку. Если вставить в неё данные от пользователя, он сможет дописать свою команду:

// src/server.js
// Опасно: exec(`convert ${fileName} out.png`)
// fileName = 'a.jpg; rm -rf ~' выполнит вторую команду

Используйте execFile() или spawn() с массивом аргументов: каждый аргумент передаётся программе как есть и не разбирается оболочкой.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.