Skip to content

Commit fe5ca3f

Browse files
committed
child_process: support promisified exec(File)
Author: Benjamin Gruenbaum <[email protected]> Author: Anna Henningsen <[email protected]> PR-URL: #12442 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Myles Borins <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: William Kapke <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Teddy Katz <[email protected]>
1 parent fbcb4f5 commit fe5ca3f

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

doc/api/child_process.md

+31
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,23 @@ child runs longer than `timeout` milliseconds.
214214
*Note: Unlike the exec(3) POSIX system call, `child_process.exec()` does not
215215
replace the existing process and uses a shell to execute the command.*
216216

217+
If this method is invoked as its [`util.promisify()`][]ed version, it returns
218+
a Promise for an object with `stdout` and `stderr` properties.
219+
220+
For example:
221+
222+
```js
223+
const util = require('util');
224+
const exec = util.promisify(require('child_process').exec);
225+
226+
async function lsExample() {
227+
const {stdout, stderr} = await exec('ls');
228+
console.log('stdout:', stdout);
229+
console.log('stderr:', stderr);
230+
}
231+
lsExample();
232+
```
233+
217234
### child_process.execFile(file[, args][, options][, callback])
218235
<!-- YAML
219236
added: v0.1.91
@@ -263,6 +280,19 @@ can be used to specify the character encoding used to decode the stdout and
263280
stderr output. If `encoding` is `'buffer'`, or an unrecognized character
264281
encoding, `Buffer` objects will be passed to the callback instead.
265282

283+
If this method is invoked as its [`util.promisify()`][]ed version, it returns
284+
a Promise for an object with `stdout` and `stderr` properties.
285+
286+
```js
287+
const util = require('util');
288+
const execFile = util.promisify(require('child_process').execFile);
289+
async function getVersion() {
290+
const {stdout} = await execFile('node', ['--version']);
291+
console.log(stdout);
292+
}
293+
getVersion();
294+
```
295+
266296
### child_process.fork(modulePath[, args][, options])
267297
<!-- YAML
268298
added: v0.5.0
@@ -1269,4 +1299,5 @@ to `stdout` although there are only 4 characters.
12691299
[`process.on('message')`]: process.html#process_event_message
12701300
[`process.send()`]: process.html#process_process_send_message_sendhandle_options_callback
12711301
[`stdio`]: #child_process_options_stdio
1302+
[`util.promisify()`]: util.html#util_util_promisify_original
12721303
[synchronous counterparts]: #child_process_synchronous_process_creation

lib/child_process.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
'use strict';
2323

2424
const util = require('util');
25-
const { deprecate, convertToValidSignal } = require('internal/util');
25+
const {
26+
deprecate, convertToValidSignal, customPromisifyArgs
27+
} = require('internal/util');
2628
const debug = util.debuglog('child_process');
2729

2830
const uv = process.binding('uv');
@@ -138,6 +140,9 @@ exports.exec = function(command /*, options, callback*/) {
138140
opts.callback);
139141
};
140142

143+
Object.defineProperty(exports.exec, customPromisifyArgs,
144+
{ value: ['stdout', 'stderr'], enumerable: false });
145+
141146

142147
exports.execFile = function(file /*, args, options, callback*/) {
143148
var args = [];
@@ -333,6 +338,9 @@ exports.execFile = function(file /*, args, options, callback*/) {
333338
return child;
334339
};
335340

341+
Object.defineProperty(exports.execFile, customPromisifyArgs,
342+
{ value: ['stdout', 'stderr'], enumerable: false });
343+
336344
const _deprecatedCustomFds = deprecate(
337345
function deprecateCustomFds(options) {
338346
options.stdio = options.customFds.map(function mapCustomFds(fd) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const child_process = require('child_process');
5+
const { promisify } = require('util');
6+
7+
common.crashOnUnhandledRejection();
8+
9+
const exec = promisify(child_process.exec);
10+
const execFile = promisify(child_process.execFile);
11+
12+
{
13+
exec(`${process.execPath} -p 42`).then(common.mustCall((obj) => {
14+
assert.deepStrictEqual(obj, { stdout: '42\n', stderr: '' });
15+
}));
16+
}
17+
18+
{
19+
execFile(process.execPath, ['-p', '42']).then(common.mustCall((obj) => {
20+
assert.deepStrictEqual(obj, { stdout: '42\n', stderr: '' });
21+
}));
22+
}
23+
24+
{
25+
exec('doesntexist').catch(common.mustCall((err) => {
26+
assert(err.message.includes('doesntexist'));
27+
}));
28+
}
29+
30+
{
31+
execFile('doesntexist', ['-p', '42']).catch(common.mustCall((err) => {
32+
assert(err.message.includes('doesntexist'));
33+
}));
34+
}

0 commit comments

Comments
 (0)