Ich benutze die Bluebird-Versprechensbibliothek unter Node.js, es ist großartig! Aber ich habe eine Frage:
Wenn Sie sich die Dokumentation von child_process.exec und child_process.execFile von Node ansehen , können Sie feststellen, dass beide Funktionen ein ChildProcess-Objekt zurückgeben.
Was ist der empfohlene Weg, um solche Funktionen zu versprechen?
Beachten Sie, dass Folgendes funktioniert (ich erhalte ein Promise-Objekt):
var Promise = require('bluebird');
var execAsync = Promise.promisify(require('child_process').exec);
var execFileAsync = Promise.promisify(require('child_process').execFile);
Aber wie kann man auf den ursprünglichen Rückgabewert der ursprünglichen Node.js-Funktionen zugreifen? (In diesen Fällen müsste ich auf die ursprünglich zurückgegebenen ChildProcess-Objekte zugreifen können.)
Jeder Vorschlag wäre dankbar!
BEARBEITEN:
Hier ist ein Beispielcode, der den Rückgabewert der Funktion child_process.exec verwendet:
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);
});
Wenn ich jedoch die versprochene Version der exec-Funktion (execAsync von oben) verwenden würde, wäre der Rückgabewert ein Versprechen, kein ChildProcess-Objekt. Dies ist das eigentliche Problem, über das ich spreche.
quelle
ChildProcess
Instanz? Ein Codebeispiel, wie Sie die gewünschte Funktion verwenden möchten, wäre hilfreich.prg <input >output
. Aber jetzt muss ich alles entkommen (sowohl unter Windows als auch unter * nix) ...const {stdout, stderr} = await exec('echo test')
Antworten:
Es hört sich so an, als würden Sie zwei Dinge aus dem Anruf zurückgeben möchten:
Also "der empfohlene Weg, solche Funktionen zu versprechen"? Tu es nicht .
Du bist außerhalb der Konvention. Von Funktionen, die Versprechen zurückgeben, wird erwartet, dass sie ein Versprechen zurückgeben, und das war's. Sie könnten ein Objekt mit zwei Mitgliedern zurückgeben (ChildProcess & das Versprechen), aber das verwirrt die Leute nur.
Ich würde vorschlagen, die nicht versprochene Funktion aufzurufen und ein Versprechen zu erstellen, das auf dem zurückgegebenen childProcess basiert. (Vielleicht wickeln Sie das in eine Hilfsfunktion)
Auf diese Weise ist es für die nächste Person, die den Code liest, ziemlich explizit.
Etwas wie:
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); });
quelle
child.addListener('exit', (code, signal) => { if (code === 0) { resolve(); } else { reject(); } });
child.stderr.on
Rückruf wäre die Protokollierungstderr
stattstdout
klarer.parallel-mochas.js
ein ähnliches Beispiel mit ES6-Versprechungen und nicht mit der Bluebird-Abhängigkeit..catch(err) instead of using the reject handler in
Wäre es hier nicht besser, .then () `zu verwenden?Ich würde empfehlen, in die Sprache integrierte Standard-JS-Versprechen über eine zusätzliche Bibliotheksabhängigkeit wie Bluebird zu verwenden.
Wenn Sie Node 10+ verwenden, empfehlen die Dokumente von Node.js,
util.promisify
einPromise<{ stdout, stderr }>
Objekt zurückzugeben. Siehe ein Beispiel unten:const util = require('util'); const exec = util.promisify(require('child_process').exec); async function lsExample() { try { const { stdout, stderr } = await exec('ls'); console.log('stdout:', stdout); console.log('stderr:', stderr); } catch (e) { console.error(e); // should contain code (exit code) and signal (that caused the termination). } } lsExample()
Behandeln Sie Fehler zuerst von
stderr
.quelle
Hier ist ein anderer Weg:
function execPromise(command) { return new Promise(function(resolve, reject) { exec(command, (error, stdout, stderr) => { if (error) { reject(error); return; } resolve(stdout.trim()); }); }); }
Verwenden Sie die Funktion:
execPromise(command).then(function(result) { console.log(result); }).catch(function(e) { console.error(e.message); });
Oder mit async / warte:
try { var result = await execPromise(command); } catch (e) { console.error(e.message); }
quelle
util.promisify
und dann darauf zugreifen.stdout
.const execAsync = require('util').promisify(require('child_process').exec);
Es gibt wahrscheinlich keine gute Möglichkeit, die alle Anwendungsfälle abdeckt. In begrenzten Fällen können Sie jedoch Folgendes tun:
/** * 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); } }); }
Dies akzeptiert
opts.stdout
undopts.stderr
argumentiert, so dass stdio aus dem untergeordneten Prozess erfasst werden kann.Zum Beispiel:
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!'));
Oder einfach:
execp('ls ./', { stdout: process.stdout, stderr: process.stderr }).then(() => console.log('done!'));
quelle
Ich möchte nur erwähnen, dass es ein nettes Tool gibt, das Ihr Problem vollständig löst:
https://www.npmjs.com/package/core-worker
Dieses Paket erleichtert die Abwicklung von Prozessen erheblich.
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();
oder kombinieren Sie diese Funktionen:
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 */);
quelle
Seit Node v12 ermöglicht das eingebaute Objekt
util.promisify
den Zugriff auf dasChildProcess
Objekt in den zurückgegebenenPromise
integrierten Funktionen, wo es durch den nicht versprochenen Aufruf zurückgegeben worden wäre. Aus den Dokumenten :Dies erfüllt korrekt und einfach die Notwendigkeit, auf
ChildProcess
die ursprüngliche Frage zuzugreifen , und macht andere Antworten veraltet, vorausgesetzt, dass Node v12 + verwendet werden kann.Durch Anpassen des vom Fragesteller bereitgestellten Beispiels (und des prägnanten Stils) kann der Zugriff auf das
ChildProcess
wie folgt erreicht werden:const util = require('util'); const exec = util.promisify(require('child_process').exec); const promise = exec('node ./commands/server.js'); const child = promise.child; 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); }); // i.e. can then await for promisified exec call to complete const { stdout, stderr } = await promise;
quelle
Hier ist meins. Es geht nicht um stdin oder stdout. Wenn Sie diese benötigen, verwenden Sie eine der anderen Antworten auf dieser Seite. :) :)
// promisify `child_process` // This is a very nice trick :-) this.promiseFromChildProcess = function (child) { return new Promise((resolve, reject) => { child.addListener('error', (code, signal) => { console.log('ChildProcess error', code, signal); reject(code); }); child.addListener('exit', (code, signal) => { if (code === 0) { resolve(code); } else { console.log('ChildProcess error', code, signal); reject(code); } }); }); };
quelle