summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorawait-ovo <13152410380@163.com>2023-07-03 03:11:34 +0800
committerGitHub <noreply@github.com>2023-07-02 19:11:34 +0000
commit0f4051a37ad23377091043206e64126003caa480 (patch)
tree3fbe98a9c78ee716665dcadaa962ea132eb9bfea /ext
parent01f0d03ae82c422c1f9551f3bfbb57daac769ddc (diff)
fix(ext/node): ignore cancelled timer when node timer refresh (#19637)
For timers that have already executed clearTimeout, there is no need to recreate a new timer when refresh is executed again.
Diffstat (limited to 'ext')
-rw-r--r--ext/node/polyfills/internal/stream_base_commons.ts2
-rw-r--r--ext/node/polyfills/internal/timers.mjs30
-rw-r--r--ext/node/polyfills/timers.ts28
3 files changed, 53 insertions, 7 deletions
diff --git a/ext/node/polyfills/internal/stream_base_commons.ts b/ext/node/polyfills/internal/stream_base_commons.ts
index 250f54c7d..d7acf729d 100644
--- a/ext/node/polyfills/internal/stream_base_commons.ts
+++ b/ext/node/polyfills/internal/stream_base_commons.ts
@@ -35,7 +35,7 @@ import {
import { isUint8Array } from "ext:deno_node/internal/util/types.ts";
import { errnoException } from "ext:deno_node/internal/errors.ts";
import { getTimerDuration, kTimeout } from "ext:deno_node/internal/timers.mjs";
-import { setUnrefTimeout } from "node:timers";
+import { clearTimeout, setUnrefTimeout } from "node:timers";
import { validateFunction } from "ext:deno_node/internal/validators.mjs";
import { codeMap } from "ext:deno_node/internal_binding/uv.ts";
import { Buffer } from "node:buffer";
diff --git a/ext/node/polyfills/internal/timers.mjs b/ext/node/polyfills/internal/timers.mjs
index d7c986917..c2e8c00e9 100644
--- a/ext/node/polyfills/internal/timers.mjs
+++ b/ext/node/polyfills/internal/timers.mjs
@@ -4,6 +4,13 @@
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ MapPrototypeDelete,
+ MapPrototypeSet,
+ SafeMap,
+} = primordials;
+
import { inspect } from "ext:deno_node/internal/util/inspect.mjs";
import { validateFunction, validateNumber } from "ext:deno_node/internal/validators.mjs";
import { ERR_OUT_OF_RANGE } from "ext:deno_node/internal/errors.ts";
@@ -22,6 +29,14 @@ export const kTimeout = Symbol("timeout");
const kRefed = Symbol("refed");
const createTimer = Symbol("createTimer");
+/**
+ * The keys in this map correspond to the key ID's in the spec's map of active
+ * timers. The values are the timeout's status.
+ *
+ * @type {Map<number, Timeout>}
+ */
+export const activeTimers = new SafeMap();
+
// Timer constructor function.
export function Timeout(callback, after, args, isRepeat, isRefed) {
if (typeof after === "number" && after > TIMEOUT_MAX) {
@@ -31,19 +46,26 @@ export function Timeout(callback, after, args, isRepeat, isRefed) {
this._onTimeout = callback;
this._timerArgs = args;
this._isRepeat = isRepeat;
+ this._destroyed = false;
this[kRefed] = isRefed;
this[kTimerId] = this[createTimer]();
}
Timeout.prototype[createTimer] = function () {
const callback = this._onTimeout;
- const cb = (...args) => callback.bind(this)(...args);
+ const cb = (...args) => {
+ if (!this._isRepeat) {
+ MapPrototypeDelete(activeTimers, this[kTimerId])
+ }
+ return callback.bind(this)(...args);
+ }
const id = this._isRepeat
? setInterval_(cb, this._idleTimeout, ...this._timerArgs)
: setTimeout_(cb, this._idleTimeout, ...this._timerArgs);
if (!this[kRefed]) {
Deno.unrefTimer(id);
}
+ MapPrototypeSet(activeTimers, id, this);
return id;
};
@@ -59,8 +81,10 @@ Timeout.prototype[inspect.custom] = function (_, options) {
};
Timeout.prototype.refresh = function () {
- clearTimeout_(this[kTimerId]);
- this[kTimerId] = this[createTimer]();
+ if (!this._destroyed) {
+ clearTimeout_(this[kTimerId]);
+ this[kTimerId] = this[createTimer]();
+ }
return this;
};
diff --git a/ext/node/polyfills/timers.ts b/ext/node/polyfills/timers.ts
index e33f44f39..2bedbe65b 100644
--- a/ext/node/polyfills/timers.ts
+++ b/ext/node/polyfills/timers.ts
@@ -3,7 +3,17 @@
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
-import { setUnrefTimeout, Timeout } from "ext:deno_node/internal/timers.mjs";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ MapPrototypeGet,
+ MapPrototypeDelete,
+} = primordials;
+
+import {
+ activeTimers,
+ setUnrefTimeout,
+ Timeout,
+} from "ext:deno_node/internal/timers.mjs";
import { validateFunction } from "ext:deno_node/internal/validators.mjs";
import { promisify } from "ext:deno_node/internal/util.mjs";
export { setUnrefTimeout } from "ext:deno_node/internal/timers.mjs";
@@ -32,7 +42,13 @@ export function clearTimeout(timeout?: Timeout | number) {
if (timeout == null) {
return;
}
- clearTimeout_(+timeout);
+ const id = +timeout;
+ const timer = MapPrototypeGet(activeTimers, id);
+ if (timer) {
+ timeout._destroyed = true;
+ MapPrototypeDelete(activeTimers, id);
+ }
+ clearTimeout_(id);
}
export function setInterval(
callback: (...args: unknown[]) => void,
@@ -46,7 +62,13 @@ export function clearInterval(timeout?: Timeout | number | string) {
if (timeout == null) {
return;
}
- clearInterval_(+timeout);
+ const id = +timeout;
+ const timer = MapPrototypeGet(activeTimers, id);
+ if (timer) {
+ timeout._destroyed = true;
+ MapPrototypeDelete(activeTimers, id);
+ }
+ clearInterval_(id);
}
// TODO(bartlomieju): implement the 'NodeJS.Immediate' versions of the timers.
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1163ead296d84e7a3c80d71e7c81ecbd1a130e9a/types/node/v12/globals.d.ts#L1120-L1131