mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
timers: add promisify support
Add support for `util.promisify(setTimeout)` and `util.promisify(setImmediate)` as a proof-of-concept implementation. `clearTimeout()` and `clearImmediate()` do not work on those Promises. Includes documentation and tests. PR-URL: https://github.com/nodejs/node/pull/12442 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: William Kapke <william.kapke@gmail.com> Reviewed-By: Timothy Gu <timothygu99@gmail.com> Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
This commit is contained in:
parent
e965ed16c1
commit
e7c51454b0
@ -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.
|
||||
});
|
||||
|
||||
// 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
|
||||
|
||||
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
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
const TimerWrap = process.binding('timer_wrap').Timer;
|
||||
const L = require('internal/linkedlist');
|
||||
const internalUtil = require('internal/util');
|
||||
const { createPromise, promiseResolve } = process.binding('util');
|
||||
const assert = require('assert');
|
||||
const util = require('util');
|
||||
const debug = util.debuglog('timer');
|
||||
@ -364,7 +366,7 @@ exports.enroll = function(item, msecs) {
|
||||
*/
|
||||
|
||||
|
||||
exports.setTimeout = function(callback, after, arg1, arg2, arg3) {
|
||||
function setTimeout(callback, after, arg1, arg2, arg3) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new TypeError('"callback" argument must be a function');
|
||||
}
|
||||
@ -383,8 +385,16 @@ exports.setTimeout = function(callback, after, arg1, arg2, arg3) {
|
||||
}
|
||||
|
||||
return createSingleTimeout(callback, after, args);
|
||||
}
|
||||
|
||||
setTimeout[internalUtil.promisify.custom] = function(after, value) {
|
||||
const promise = createPromise();
|
||||
createSingleTimeout(promise, after, [value]);
|
||||
return promise;
|
||||
};
|
||||
|
||||
exports.setTimeout = setTimeout;
|
||||
|
||||
function createSingleTimeout(callback, after, args) {
|
||||
after *= 1; // coalesce to number or NaN
|
||||
if (!(after >= 1 && after <= TIMEOUT_MAX))
|
||||
@ -403,6 +413,8 @@ function createSingleTimeout(callback, after, args) {
|
||||
function ontimeout(timer) {
|
||||
var args = timer._timerArgs;
|
||||
var callback = timer._onTimeout;
|
||||
if (typeof callback !== 'function')
|
||||
return promiseResolve(callback, args[0]);
|
||||
if (!args)
|
||||
callback.call(timer);
|
||||
else {
|
||||
@ -687,6 +699,8 @@ function tryOnImmediate(immediate, oldTail) {
|
||||
function runCallback(timer) {
|
||||
const argv = timer._argv;
|
||||
const argc = argv ? argv.length : 0;
|
||||
if (typeof timer._callback !== 'function')
|
||||
return promiseResolve(timer._callback, argv[0]);
|
||||
switch (argc) {
|
||||
// fast-path callbacks with 0-3 arguments
|
||||
case 0:
|
||||
@ -715,7 +729,7 @@ function Immediate() {
|
||||
this.domain = process.domain;
|
||||
}
|
||||
|
||||
exports.setImmediate = function(callback, arg1, arg2, arg3) {
|
||||
function setImmediate(callback, arg1, arg2, arg3) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new TypeError('"callback" argument must be a function');
|
||||
}
|
||||
@ -740,8 +754,16 @@ exports.setImmediate = function(callback, arg1, arg2, arg3) {
|
||||
break;
|
||||
}
|
||||
return createImmediate(args, callback);
|
||||
}
|
||||
|
||||
setImmediate[internalUtil.promisify.custom] = function(value) {
|
||||
const promise = createPromise();
|
||||
createImmediate([value], promise);
|
||||
return promise;
|
||||
};
|
||||
|
||||
exports.setImmediate = setImmediate;
|
||||
|
||||
function createImmediate(args, callback) {
|
||||
// declaring it `const immediate` causes v6.0.0 to deoptimize this function
|
||||
var immediate = new Immediate();
|
||||
|
40
test/parallel/test-timers-promisified.js
Normal file
40
test/parallel/test-timers-promisified.js
Normal file
@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const timers = require('timers');
|
||||
const { promisify } = require('util');
|
||||
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
|
||||
common.crashOnUnhandledRejection();
|
||||
|
||||
const setTimeout = promisify(timers.setTimeout);
|
||||
const setImmediate = promisify(timers.setImmediate);
|
||||
|
||||
{
|
||||
const promise = setTimeout(1);
|
||||
promise.then(common.mustCall((value) => {
|
||||
assert.strictEqual(value, undefined);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const promise = setTimeout(1, 'foobar');
|
||||
promise.then(common.mustCall((value) => {
|
||||
assert.strictEqual(value, 'foobar');
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const promise = setImmediate();
|
||||
promise.then(common.mustCall((value) => {
|
||||
assert.strictEqual(value, undefined);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const promise = setImmediate('foobar');
|
||||
promise.then(common.mustCall((value) => {
|
||||
assert.strictEqual(value, 'foobar');
|
||||
}));
|
||||
}
|
Loading…
Reference in New Issue
Block a user