Как promisify процесс детского узла.exec и дочерний процесс.функции execFile с Bluebird?
Я использую библиотеку обещаний Bluebird под узлом.джей, это здорово! Но у меня вопрос:--3-->
Если вы посмотрите на документацию узла child_process.exec и child_process.execFile вы можете видеть, что обе эти функции возвращают объект ChildProcess.
Так что рекомендуемый способ promisify такие функции?
обратите внимание, что следующие работы (я вам обещаю объект):
var Promise = require('bluebird');
var execAsync = Promise.promisify(require('child_process').exec);
var execFileAsync = Promise.promisify(require('child_process').execFile);
но как получить доступ к исходному возвращаемому значению исходного узла.функции js? (В этих случаях мне нужно будет иметь доступ к первоначально возвращенным объектам ChildProcess.)
любое предложение было бы оценено!
EDIT:
вот пример кода, который использует возвращаемое значение child_process.функция exec:
var exec = require('child_process').exec;
var child = exec('node ./commands/server.js');
child.stdout.on('data', function(data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function(data) {
console.log('stderr: ' + data);
});
child.on('close', function(code) {
console.log('closing code: ' + code);
});
но если я хотел бы использовать promisified версия экзек функция (execAsync сверху), то возвращаемое значение будет обещанием, а не объектом ChildProcess. Это настоящая проблема, о которой я говорю.
4 ответов
похоже, вы хотели бы вернуть две вещи из вызова:
- ChildProcess
- обещание, которое разрешается, когда ChildProcess завершает
Так "рекомендуемый способ promisify такие функции"? не.
вы вне конвенции. Ожидается, что функции возврата обещаний вернут обещание,и все. Вы можете вернуть объект с двумя членами (ChildProcess & promise), но это только собьет людей с толку.
Я предлагаю вызова функции unpromisified, и создавая обещание основе возвращенного childProcess. (Возможно, оберните это в вспомогательную функцию)
таким образом, это довольно ясно для следующего человека, который читает код.
что-то типа:
var Promise = require('bluebird');
var exec = require('child_process').execFile;
function promiseFromChildProcess(child) {
return new Promise(function (resolve, reject) {
child.addListener("error", reject);
child.addListener("exit", resolve);
});
}
var child = exec('ls');
promiseFromChildProcess(child).then(function (result) {
console.log('promise complete: ' + result);
}, function (err) {
console.log('promise rejected: ' + err);
});
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
child.on('close', function (code) {
console.log('closing code: ' + code);
});
вероятно, нет способа сделать красиво, который охватывает все варианты использования. Но для ограниченных случаев вы можете сделать что-то вроде этого:
/**
* Promisified child_process.exec
*
* @param cmd
* @param opts See child_process.exec node docs
* @param {stream.Writable} opts.stdout If defined, child process stdout will be piped to it.
* @param {stream.Writable} opts.stderr If defined, child process stderr will be piped to it.
*
* @returns {Promise<{ stdout: string, stderr: stderr }>}
*/
function execp(cmd, opts) {
opts || (opts = {});
return new Promise((resolve, reject) => {
const child = exec(cmd, opts,
(err, stdout, stderr) => err ? reject(err) : resolve({
stdout: stdout,
stderr: stderr
}));
if (opts.stdout) {
child.stdout.pipe(opts.stdout);
}
if (opts.stderr) {
child.stderr.pipe(opts.stderr);
}
});
}
Это можно opts.stdout
и opts.stderr
аргументы, чтобы stdio можно было захватить из дочернего процесса.
например:
execp('ls ./', {
stdout: new stream.Writable({
write: (chunk, enc, next) => {
console.log(chunk.toString(enc));
next();
}
}),
stderr: new stream.Writable({
write: (chunk, enc, next) => {
console.error(chunk.toString(enc));
next();
}
})
}).then(() => console.log('done!'));
или просто:
execp('ls ./', {
stdout: process.stdout,
stderr: process.stderr
}).then(() => console.log('done!'));
просто хочу упомянуть, что есть хороший инструмент, который полностью решит вашу проблему:
https://www.npmjs.com/package/core-worker
этот пакет упрощает обработку процессов.
import { process } from "CoreWorker";
import fs from "fs";
const result = await process("node Server.js", "Server is ready.").ready(1000);
const result = await process("cp path/to/file /newLocation/newFile").death();
или совмещать эти функции:
import { process } from "core-worker";
const simpleChat = process("node chat.js", "Chat ready");
setTimeout(() => simpleChat.kill(), 360000); // wait an hour and close the chat
simpleChat.ready(500)
.then(console.log.bind(console, "You are now able to send messages."))
.then(::simpleChat.death)
.then(console.log.bind(console, "Chat closed"))
.catch(() => /* handle err */);
вот еще один способ:
function execPromise(command) {
return new Promise(function(resolve, reject) {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
resolve(stdout.trim());
});
});
}
execPromise(command).then(function(result) {
console.log(result);
}).catch(function(error) {
console.error(e.message);
});
или с async / await:
try {
var result = await execPromise(command);
} catch (e) {
console.error(e.message);
}