From e2442bb7efcc5db996e806428dc646c6e2f5dcc6 Mon Sep 17 00:00:00 2001 From: Moshe Atlow Date: Wed, 5 Jul 2023 16:39:38 +0300 Subject: [PATCH] timers: support Symbol.dispose PR-URL: https://github.com/nodejs/node/pull/48633 Reviewed-By: Zeyu "Alex" Yang Reviewed-By: Benjamin Gruenbaum Reviewed-By: Robert Nagy --- doc/api/timers.md | 20 ++++++++++++++++++++ lib/internal/per_context/primordials.js | 2 +- lib/timers.js | 9 +++++++++ test/parallel/test-timers-dispose.js | 18 ++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-timers-dispose.js diff --git a/doc/api/timers.md b/doc/api/timers.md index 5fe5a6943adc48..768f59fd6f1d2b 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -63,6 +63,16 @@ loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the `Immediate` object's callback is invoked. Calling `immediate.unref()` multiple times will have no effect. +### `immediate[Symbol.dispose]()` + + + +> Stability: 1 - Experimental + +Cancels the immediate. This is similar to calling `clearImmediate()`. + ## Class: `Timeout` This object is created internally and is returned from [`setTimeout()`][] and @@ -157,6 +167,16 @@ across [`worker_threads`][] it must first be passed to the correct thread. This allows enhanced compatibility with browser `setTimeout()` and `setInterval()` implementations. +### `timeout[Symbol.dispose]()` + + + +> Stability: 1 - Experimental + +Cancels the timeout. + ## Scheduling timers A timer in Node.js is an internal construct that calls a given function after diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index 98e9a0754a8a76..64438ddd5219f1 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -228,7 +228,7 @@ function copyPrototype(src, dest, prefix) { copyPrototype(original.prototype, primordials, `${name}Prototype`); }); -// Define Symbol.Dispose and Symbol.AsyncDispose +// Define Symbol.dispose and Symbol.asyncDispose // Until these are defined by the environment. // TODO(MoLow): Remove this polyfill once Symbol.dispose and Symbol.asyncDispose are available in V8. primordials.SymbolDispose ??= primordials.SymbolFor('nodejs.dispose'); diff --git a/lib/timers.js b/lib/timers.js index 56c733de9ce6d0..ad58cf61f1309f 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -24,6 +24,7 @@ const { MathTrunc, ObjectDefineProperty, + SymbolDispose, SymbolToPrimitive, } = primordials; @@ -253,6 +254,10 @@ Timeout.prototype.close = function() { return this; }; +Timeout.prototype[SymbolDispose] = function() { + clearTimeout(this); +}; + /** * Coerces a `Timeout` to a primitive. * @returns {number} @@ -338,6 +343,10 @@ function clearImmediate(immediate) { immediateQueue.remove(immediate); } +Immediate.prototype[SymbolDispose] = function() { + clearImmediate(this); +}; + module.exports = { setTimeout, clearTimeout, diff --git a/test/parallel/test-timers-dispose.js b/test/parallel/test-timers-dispose.js new file mode 100644 index 00000000000000..a75916b4184651 --- /dev/null +++ b/test/parallel/test-timers-dispose.js @@ -0,0 +1,18 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); + +const timer = setTimeout(common.mustNotCall(), 10); +const interval = setInterval(common.mustNotCall(), 10); +const immediate = setImmediate(common.mustNotCall()); + +timer[Symbol.dispose](); +interval[Symbol.dispose](); +immediate[Symbol.dispose](); + + +process.on('exit', () => { + assert.strictEqual(timer._destroyed, true); + assert.strictEqual(interval._destroyed, true); + assert.strictEqual(immediate._destroyed, true); +});