-
Notifications
You must be signed in to change notification settings - Fork 30.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
util: add util.promisify() #12442
util: add util.promisify() #12442
Changes from all commits
059f296
99da8e8
3ea2301
e965ed1
e7c5145
fbcb4f5
fe5ca3f
faf6654
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -214,6 +214,23 @@ child runs longer than `timeout` milliseconds. | |
*Note: Unlike the exec(3) POSIX system call, `child_process.exec()` does not | ||
replace the existing process and uses a shell to execute the command.* | ||
|
||
If this method is invoked as its [`util.promisify()`][]ed version, it returns | ||
a Promise for an object with `stdout` and `stderr` properties. | ||
|
||
For example: | ||
|
||
```js | ||
const util = require('util'); | ||
const exec = util.promisify(require('child_process').exec); | ||
|
||
async function lsExample() { | ||
const {stdout, stderr} = await exec('ls'); | ||
console.log('stdout:', stdout); | ||
console.log('stderr:', stderr); | ||
} | ||
lsExample(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I might be pedantic here, but we are ignoring the returned promise. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @thefourtheye Yes … got a better suggestion? Just leave this line out? ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mmmm, to think of it, that sounds better to me. |
||
``` | ||
|
||
### child_process.execFile(file[, args][, options][, callback]) | ||
<!-- YAML | ||
added: v0.1.91 | ||
|
@@ -263,6 +280,19 @@ can be used to specify the character encoding used to decode the stdout and | |
stderr output. If `encoding` is `'buffer'`, or an unrecognized character | ||
encoding, `Buffer` objects will be passed to the callback instead. | ||
|
||
If this method is invoked as its [`util.promisify()`][]ed version, it returns | ||
a Promise for an object with `stdout` and `stderr` properties. | ||
|
||
```js | ||
const util = require('util'); | ||
const execFile = util.promisify(require('child_process').execFile); | ||
async function getVersion() { | ||
const {stdout} = await execFile('node', ['--version']); | ||
console.log(stdout); | ||
} | ||
getVersion(); | ||
``` | ||
|
||
### child_process.fork(modulePath[, args][, options]) | ||
<!-- YAML | ||
added: v0.5.0 | ||
|
@@ -1269,4 +1299,5 @@ to `stdout` although there are only 4 characters. | |
[`process.on('message')`]: process.html#process_event_message | ||
[`process.send()`]: process.html#process_process_send_message_sendhandle_options_callback | ||
[`stdio`]: #child_process_options_stdio | ||
[`util.promisify()`]: util.html#util_util_promisify_original | ||
[synchronous counterparts]: #child_process_synchronous_process_creation |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1612,6 +1612,9 @@ If `position` is `null`, data will be read from the current file position. | |
|
||
The callback is given the three arguments, `(err, bytesRead, buffer)`. | ||
|
||
If this method is invoked as its [`util.promisify()`][]ed version, it returns | ||
a Promise for an object with `bytesRead` and `buffer` properties. | ||
|
||
## fs.readdir(path[, options], callback) | ||
<!-- YAML | ||
added: v0.1.8 | ||
|
@@ -2393,8 +2396,11 @@ an integer specifying the number of bytes to write. | |
should be written. If `typeof position !== 'number'`, the data will be written | ||
at the current position. See pwrite(2). | ||
|
||
The callback will be given three arguments `(err, written, buffer)` where | ||
`written` specifies how many _bytes_ were written from `buffer`. | ||
The callback will be given three arguments `(err, bytesWritten, buffer)` where | ||
`bytesWritten` specifies how many _bytes_ were written from `buffer`. | ||
|
||
If this method is invoked as its [`util.promisify()`][]ed version, it returns | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Going to add an example here too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did addaleax@07acf08 for timers, but not sure I can add an example here as there is no non-promise version here. |
||
a Promise for an object with `bytesWritten` and `buffer` properties. | ||
|
||
Note that it is unsafe to use `fs.write` multiple times on the same file | ||
without waiting for the callback. For this scenario, | ||
|
@@ -2810,6 +2816,7 @@ The following constants are meant for use with the [`fs.Stats`][] object's | |
[`net.Socket`]: net.html#net_class_net_socket | ||
[`stat()`]: fs.html#fs_fs_stat_path_callback | ||
[`util.inspect(stats)`]: util.html#util_util_inspect_object_options | ||
[`util.promisify()`]: util.html#util_util_promisify_original | ||
[Caveats]: #fs_caveats | ||
[Common System Errors]: errors.html#errors_common_system_errors | ||
[FS Constants]: #fs_fs_constants_1 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,6 +85,27 @@ next event loop iteration. | |
|
||
If `callback` is not a function, a [`TypeError`][] will be thrown. | ||
|
||
*Note*: This method has a custom variant for promises that is available using | ||
[`util.promisify()`][]: | ||
|
||
```js | ||
const util = require('util'); | ||
const setImmediatePromise = util.promisify(setImmediate); | ||
|
||
setImmediatePromise('foobar').then((value) => { | ||
// value === 'foobar' (passing values is optional) | ||
// This is executed after all I/O callbacks. | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An async function example would be cool as well. |
||
|
||
// or with async function | ||
async function timerExample() { | ||
console.log('Before I/O callbacks'); | ||
await setImmediatePromise(); | ||
console.log('After I/O callbacks'); | ||
} | ||
timerExample(); | ||
``` | ||
|
||
### setInterval(callback, delay[, ...args]) | ||
<!-- YAML | ||
added: v0.0.1 | ||
|
@@ -126,12 +147,28 @@ will be set to `1`. | |
|
||
If `callback` is not a function, a [`TypeError`][] will be thrown. | ||
|
||
*Note*: This method has a custom variant for promises that is available using | ||
[`util.promisify()`][]: | ||
|
||
```js | ||
const util = require('util'); | ||
const setTimeoutPromise = util.promisify(setTimeout); | ||
|
||
setTimeoutPromise(40, 'foobar').then((value) => { | ||
// value === 'foobar' (passing values is optional) | ||
// This is executed after about 40 milliseconds. | ||
}); | ||
``` | ||
|
||
## Cancelling Timers | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps add a note here that it is not yet possible to cancel a timer promise given that there is no standard way of canceling a promise. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done, but I didn’t mention the reason for why that doesn’t exist – I don’t think we do that in our docs |
||
The [`setImmediate()`][], [`setInterval()`][], and [`setTimeout()`][] methods | ||
each return objects that represent the scheduled timers. These can be used to | ||
cancel the timer and prevent it from triggering. | ||
|
||
It is not possible to cancel timers that were created using the promisified | ||
variants of [`setImmediate()`][], [`setTimeout()`][]. | ||
|
||
### clearImmediate(immediate) | ||
<!-- YAML | ||
added: v0.9.1 | ||
|
@@ -168,4 +205,5 @@ Cancels a `Timeout` object created by [`setTimeout()`][]. | |
[`setImmediate()`]: timers.html#timers_setimmediate_callback_args | ||
[`setInterval()`]: timers.html#timers_setinterval_callback_delay_args | ||
[`setTimeout()`]: timers.html#timers_settimeout_callback_delay_args | ||
[`util.promisify()`]: util.html#util_util_promisify_original | ||
[the Node.js Event Loop]: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -399,6 +399,86 @@ util.inspect.defaultOptions.maxArrayLength = null; | |
console.log(arr); // logs the full array | ||
``` | ||
|
||
## util.promisify(original) | ||
<!-- YAML | ||
added: REPLACEME | ||
--> | ||
|
||
* `original` {Function} | ||
|
||
Takes a function following the common Node.js callback style, i.e. taking a | ||
`(err, value) => ...` callback as the last argument, and returns a version | ||
that returns promises. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if a Sync function is passed to this? Is the behavior undefined? Is there any way that we could define any reasonable behavior? (I doubt it... I'm +1 on simply saying that the behavior is undefined) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean Sync as in calls the callback right away or as in never calls the callback? In the latter case, my expectation would be that the promise is neither resolved nor rejected - that seems well-defined. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sync functions that throw reject the promise ( In other words, it works just fine. |
||
|
||
For example: | ||
|
||
```js | ||
const util = require('util'); | ||
const fs = require('fs'); | ||
|
||
const stat = util.promisify(fs.stat); | ||
stat('.').then((stats) => { | ||
// Do something with `stats` | ||
}).catch((error) => { | ||
// Handle the error. | ||
}); | ||
``` | ||
|
||
Or, equivalently using `async function`s: | ||
|
||
```js | ||
const util = require('util'); | ||
const fs = require('fs'); | ||
|
||
const stat = util.promisify(fs.stat); | ||
|
||
async function callStat() { | ||
const stats = await stat('.'); | ||
console.log(`This directory is owned by ${stats.uid}`); | ||
} | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Everywhere else the function invocation is also shown. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @thefourtheye I’m confused now, this seems to be the opposite of #12442 (comment) … would you prefer an extra There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry. We can get rid of the function calls. |
||
|
||
If there is an `original[util.promisify.custom]` property present, `promisify` | ||
will return its value, see [Custom promisified functions][]. | ||
|
||
`promisify()` assumes that `original` is a function taking a callback as its | ||
final argument in all cases, and the returned function will result in undefined | ||
behaviour if it does not. | ||
|
||
### Custom promisified functions | ||
|
||
Using the `util.promisify.custom` symbol one can override the return value of | ||
[`util.promisify()`][]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should likely go into more detail on why someone would want to do this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a sentence on what I assume is the main use case (alternative callback formats) |
||
|
||
```js | ||
const util = require('util'); | ||
|
||
function doSomething(foo, callback) { | ||
// ... | ||
} | ||
|
||
doSomething[util.promisify.custom] = function(foo) { | ||
return getPromiseSomehow(); | ||
}; | ||
|
||
const promisified = util.promisify(doSomething); | ||
console.log(promisified === doSomething[util.promisify.custom]); | ||
// prints 'true' | ||
``` | ||
|
||
This can be useful for cases where the original function does not follow the | ||
standard format of taking an error-first callback as the last argument. | ||
|
||
### util.promisify.custom | ||
<!-- YAML | ||
added: REPLACEME | ||
--> | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. * {symbol} |
||
* {symbol} | ||
|
||
A Symbol that can be used to declare custom promisified variants of functions, | ||
see [Custom promisified functions][]. | ||
|
||
## Deprecated APIs | ||
|
||
The following APIs have been deprecated and should no longer be used. Existing | ||
|
@@ -878,7 +958,9 @@ Deprecated predecessor of `console.log`. | |
[`console.error()`]: console.html#console_console_error_data_args | ||
[`console.log()`]: console.html#console_console_log_data_args | ||
[`util.inspect()`]: #util_util_inspect_object_options | ||
[`util.promisify()`]: #util_util_promisify_original | ||
[Custom inspection functions on Objects]: #util_custom_inspection_functions_on_objects | ||
[Customizing `util.inspect` colors]: #util_customizing_util_inspect_colors | ||
[Custom promisified functions]: #util_custom_promisified_functions | ||
[constructor]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor | ||
[semantically incompatible]: https://github.com/nodejs/node/issues/4179 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that it is quite tedious to do so, but examples would be good for these
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addaleax@8580fb2