diff options
author | James M Snell <jasnell@gmail.com> | 2020-11-06 07:07:43 -0800 |
---|---|---|
committer | Node.js GitHub Bot <github-bot@iojs.org> | 2020-11-09 08:23:10 +0000 |
commit | aa1eb1fd597f68c6cb67c2a4d631a8d66f2cb94e (patch) | |
tree | 0533a41b48cc8afa9010015c8fc9c357508d15ff /lib/timers | |
parent | 1a6d4dce6db09cb58cb77714cdcb28d84a7c7073 (diff) | |
download | node-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.js | 42 |
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 = { |