summaryrefslogtreecommitdiff
path: root/lib/timers
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2020-11-06 07:07:43 -0800
committerNode.js GitHub Bot <github-bot@iojs.org>2020-11-09 08:23:10 +0000
commitaa1eb1fd597f68c6cb67c2a4d631a8d66f2cb94e (patch)
tree0533a41b48cc8afa9010015c8fc9c357508d15ff /lib/timers
parent1a6d4dce6db09cb58cb77714cdcb28d84a7c7073 (diff)
downloadnode-new-aa1eb1fd597f68c6cb67c2a4d631a8d66f2cb94e.tar.gz
timers: cleanup abort listener on awaitable timers
Co-authored-by: Benjamin Gruenbaum <benjamingr@gmail.com> Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/36006 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'lib/timers')
-rw-r--r--lib/timers/promises.js42
1 files changed, 26 insertions, 16 deletions
diff --git a/lib/timers/promises.js b/lib/timers/promises.js
index ef1e6437d4..eba8c1e503 100644
--- a/lib/timers/promises.js
+++ b/lib/timers/promises.js
@@ -2,6 +2,7 @@
const {
Promise,
+ PromisePrototypeFinally,
PromiseReject,
} = primordials;
@@ -24,6 +25,13 @@ const lazyDOMException = hideStackFrames((message, name) => {
return new DOMException(message, name);
});
+function cancelListenerHandler(clear, reject) {
+ if (!this._destroyed) {
+ clear(this);
+ reject(lazyDOMException('The operation was aborted', 'AbortError'));
+ }
+}
+
function setTimeout(after, value, options = {}) {
const args = value !== undefined ? [value] : value;
if (options == null || typeof options !== 'object') {
@@ -58,20 +66,21 @@ function setTimeout(after, value, options = {}) {
return PromiseReject(
lazyDOMException('The operation was aborted', 'AbortError'));
}
- return new Promise((resolve, reject) => {
+ let oncancel;
+ const ret = new Promise((resolve, reject) => {
const timeout = new Timeout(resolve, after, args, false, true);
if (!ref) timeout.unref();
insert(timeout, timeout._idleTimeout);
if (signal) {
- signal.addEventListener('abort', () => {
- if (!timeout._destroyed) {
- // eslint-disable-next-line no-undef
- clearTimeout(timeout);
- reject(lazyDOMException('The operation was aborted', 'AbortError'));
- }
- }, { once: true });
+ // eslint-disable-next-line no-undef
+ oncancel = cancelListenerHandler.bind(timeout, clearTimeout, reject);
+ signal.addEventListener('abort', oncancel);
}
});
+ return oncancel !== undefined ?
+ PromisePrototypeFinally(
+ ret,
+ () => signal.removeEventListener('abort', oncancel)) : ret;
}
function setImmediate(value, options = {}) {
@@ -107,19 +116,20 @@ function setImmediate(value, options = {}) {
return PromiseReject(
lazyDOMException('The operation was aborted', 'AbortError'));
}
- return new Promise((resolve, reject) => {
+ let oncancel;
+ const ret = new Promise((resolve, reject) => {
const immediate = new Immediate(resolve, [value]);
if (!ref) immediate.unref();
if (signal) {
- signal.addEventListener('abort', () => {
- if (!immediate._destroyed) {
- // eslint-disable-next-line no-undef
- clearImmediate(immediate);
- reject(lazyDOMException('The operation was aborted', 'AbortError'));
- }
- }, { once: true });
+ // eslint-disable-next-line no-undef
+ oncancel = cancelListenerHandler.bind(immediate, clearImmediate, reject);
+ signal.addEventListener('abort', oncancel);
}
});
+ return oncancel !== undefined ?
+ PromisePrototypeFinally(
+ ret,
+ () => signal.removeEventListener('abort', oncancel)) : ret;
}
module.exports = {