Skip to content
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

lib: add Timer/Immediate to promisifyed setTimer/setImmediate #29521

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 19 additions & 4 deletions doc/api/timers.md
Expand Up @@ -151,8 +151,9 @@ next event loop iteration.

If `callback` is not a function, a [`TypeError`][] will be thrown.

This method has a custom variant for promises that is available using
[`util.promisify()`][]:
If this method is invoked as its [`util.promisify()`][]ed version, it returns a
Promise. The created `Immediate` is attached to the Promise as a `immediate`
BridgeAR marked this conversation as resolved.
Show resolved Hide resolved
property.

```js
const util = require('util');
Expand All @@ -170,6 +171,13 @@ async function timerExample() {
console.log('After I/O callbacks');
}
timerExample();

// You can access the immediate on promise.immediate
const promise = setImmediatePromise();
promise.then(() => {
// This callback is never called because the Immediate is cleared
});
clearImmediate(promise.immediate);
```

### setInterval(callback, delay[, ...args])
Expand Down Expand Up @@ -213,8 +221,9 @@ will be set to `1`. Non-integer delays are truncated to an integer.

If `callback` is not a function, a [`TypeError`][] will be thrown.

This method has a custom variant for promises that is available using
[`util.promisify()`][]:
If this method is invoked as its [`util.promisify()`][]ed version, it returns a
Promise. The created `Timeout` is attached to the Promise as a `timeout`
property.

```js
const util = require('util');
Expand All @@ -224,6 +233,12 @@ setTimeoutPromise(40, 'foobar').then((value) => {
// value === 'foobar' (passing values is optional)
// This is executed after about 40 milliseconds.
});

const promise = setTimeoutPromise(40, 'foobar');
promise.then((value) => {
// This is never executed because the timeout is cleared
});
clearTimeout(promise.timeout);
```

## Cancelling Timers
Expand Down
13 changes: 9 additions & 4 deletions lib/timers.js
Expand Up @@ -147,9 +147,11 @@ function setTimeout(callback, after, arg1, arg2, arg3) {

setTimeout[customPromisify] = function(after, value) {
const args = value !== undefined ? [value] : value;
return new Promise((resolve) => {
active(new Timeout(resolve, after, args, false));
});
let resolve;
const promise = new Promise((res) => resolve = res);
promise.timeout = new Timeout(resolve, after, args, false);
active(promise.timeout);
return promise;
};

function clearTimeout(timer) {
Expand Down Expand Up @@ -272,7 +274,10 @@ function setImmediate(callback, arg1, arg2, arg3) {
}

setImmediate[customPromisify] = function(value) {
return new Promise((resolve) => new Immediate(resolve, [value]));
let resolve;
const promise = new Promise((res) => resolve = res);
promise.immediate = new Immediate(resolve, [value]);
return promise;
};

function clearImmediate(immediate) {
Expand Down
10 changes: 10 additions & 0 deletions test/parallel/test-timer-immediate-async-cleared.js
@@ -0,0 +1,10 @@
'use strict';
const { mustNotCall } = require('../common');
const { promisify } = require('util');

const setImmediateAsync = promisify(setImmediate);

const expected = ['foo', 'bar', 'baz'];
const promise = setImmediateAsync(...expected);
promise.then(() => mustNotCall('expected immediate to be cleared'));
clearImmediate(promise.immediate);
12 changes: 12 additions & 0 deletions test/parallel/test-timer-immediate-async.js
@@ -0,0 +1,12 @@
'use strict';
require('../common');
const { strictEqual } = require('assert');
const { promisify } = require('util');

const setImmediateAsync = promisify(setImmediate);

const expected = ['foo', 'bar', 'baz'];
// N.B. the promisified version of setImmediate will resolve with the _first_
// value, not an array of all values.
setImmediateAsync(...expected)
.then((actual) => strictEqual(actual, expected[0]));
10 changes: 10 additions & 0 deletions test/parallel/test-timer-timeout-async-cleared.js
@@ -0,0 +1,10 @@
'use strict';
const { mustNotCall } = require('../common');
const { promisify } = require('util');

const setTimeoutAsync = promisify(setTimeout);

const expected = ['foo', 'bar', 'baz'];
const promise = setTimeoutAsync(10, ...expected);
promise.then(() => mustNotCall('expected timeout to be cleared'));
clearTimeout(promise.timeout);
12 changes: 12 additions & 0 deletions test/parallel/test-timer-timeout-async.js
@@ -0,0 +1,12 @@
'use strict';
require('../common');
const { strictEqual } = require('assert');
const { promisify } = require('util');

const setTimeoutAsync = promisify(setTimeout);

const expected = ['foo', 'bar', 'baz'];
// N.B. the promisified version of setTimeout will resolve with the _first_
// value, not an array of all values.
setTimeoutAsync(10, ...expected)
.then((actual) => strictEqual(actual, expected[0]));