diff options
author | await-ovo <13152410380@163.com> | 2023-07-03 03:11:34 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-02 19:11:34 +0000 |
commit | 0f4051a37ad23377091043206e64126003caa480 (patch) | |
tree | 3fbe98a9c78ee716665dcadaa962ea132eb9bfea /ext/node/polyfills | |
parent | 01f0d03ae82c422c1f9551f3bfbb57daac769ddc (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/node/polyfills')
-rw-r--r-- | ext/node/polyfills/internal/stream_base_commons.ts | 2 | ||||
-rw-r--r-- | ext/node/polyfills/internal/timers.mjs | 30 | ||||
-rw-r--r-- | ext/node/polyfills/timers.ts | 28 |
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 |