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

timers: allow passing delay to timer.refresh() #40434

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -3242,7 +3242,7 @@ Convert them to primitive strings.
[`setTimeout()`]: timers.md#settimeoutcallback-delay-args
[`socket.bufferSize`]: net.md#socketbuffersize
[`timeout.ref()`]: timers.md#timeoutref
[`timeout.refresh()`]: timers.md#timeoutrefresh
[`timeout.refresh()`]: timers.md#timeoutrefreshdelay-resetinterval
[`timeout.unref()`]: timers.md#timeoutunref
[`tls.CryptoStream`]: tls.md#class-tlscryptostream
[`tls.SecureContext`]: tls.md#tlscreatesecurecontextoptions
Expand Down
16 changes: 12 additions & 4 deletions doc/api/timers.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,26 @@ When called, requests that the Node.js event loop _not_ exit so long as the
By default, all `Timeout` objects are "ref'ed", making it normally unnecessary
to call `timeout.ref()` unless `timeout.unref()` had been called previously.

### `timeout.refresh()`
### `timeout.refresh([delay[, resetInterval]])`

<!-- YAML
added: v10.2.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/40434
description: Added `delay` and `resetInterval` parameters.
-->

* `delay` {number} The number of milliseconds to wait before calling the
original callback.
* `resetInterval` {boolean} For an interval timer, should the interval be set to
`delay`? **Default:** `false`.
* Returns: {Timeout} a reference to `timeout`

Sets the timer's start time to the current time, and reschedules the timer to
call its callback at the previously specified duration adjusted to the current
time. This is useful for refreshing a timer without allocating a new
JavaScript object.
call its callback at the previously specified duration or the duration specified
by `delay` adjusted to the current time. This is useful for refreshing a timer
without allocating a new JavaScript object.

Using this on a timer that has already called its callback will reactivate the
timer.
Expand Down
35 changes: 24 additions & 11 deletions lib/internal/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,26 @@ function initAsyncResource(resource, type) {
if (initHooksExist())
emitInit(asyncId, type, triggerAsyncId, resource);
}

function calcAfter(after) {
after *= 1; // Coalesce to number or NaN
if (!(after >= 1 && after <= TIMEOUT_MAX)) {
if (after > TIMEOUT_MAX) {
process.emitWarning(`${after} does not fit into` +
' a 32-bit signed integer.' +
'\nTimeout duration was set to 1.',
'TimeoutOverflowWarning');
}
after = 1; // Schedule on next tick, follows browser behavior
}
return after;
}

class Timeout {
// Timer constructor function.
// The entire prototype is defined in lib/timers.js
constructor(callback, after, args, isRepeat, isRefed) {
after *= 1; // Coalesce to number or NaN
if (!(after >= 1 && after <= TIMEOUT_MAX)) {
if (after > TIMEOUT_MAX) {
process.emitWarning(`${after} does not fit into` +
' a 32-bit signed integer.' +
'\nTimeout duration was set to 1.',
'TimeoutOverflowWarning');
}
after = 1; // Schedule on next tick, follows browser behavior
}
after = calcAfter(after);

this._idleTimeout = after;
this._idlePrev = this;
Expand Down Expand Up @@ -204,7 +210,14 @@ class Timeout {
});
}

refresh() {
refresh(after, resetInterval) {
if (after !== undefined) {
after = calcAfter(after);
this._idleTimeout = after;
if (this._repeat !== null && resetInterval)
this._repeat = after;
}

if (this[kRefed])
active(this);
else
Expand Down
31 changes: 31 additions & 0 deletions test/sequential/test-timers-refresh-args.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';
require('../common');
const assert = require('assert');

const LONGER_DELAY = 1000;
const SHORTER_DELAY = 100;
let last;
let t = setTimeout(() => {
if (last !== undefined) {
assert(Date.now() - last < LONGER_DELAY);

last = undefined;
let count = 0;
t = setInterval(() => {
if (last !== undefined)
assert(Date.now() - last < LONGER_DELAY);
last = Date.now();
switch (count++) {
case 0:
t.refresh(SHORTER_DELAY, true);
break;
case 3:
clearInterval(t);
break;
}
}, LONGER_DELAY);
return;
}
last = Date.now();
t.refresh(SHORTER_DELAY);
}, LONGER_DELAY);