timers: propagate signal.reason in awaitable timers

Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/41008
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
pull/40909/head
James M Snell 2021-11-28 12:38:42 -08:00
parent 36c0ac05e6
commit a2982798e3
No known key found for this signature in database
GPG Key ID: 7341B15C070877AC
4 changed files with 38 additions and 9 deletions

View File

@ -24,10 +24,10 @@ const {
validateObject,
} = require('internal/validators');
function cancelListenerHandler(clear, reject) {
function cancelListenerHandler(clear, reject, signal) {
if (!this._destroyed) {
clear(this);
reject(new AbortError());
reject(new AbortError(undefined, { cause: signal?.reason }));
}
}
@ -57,7 +57,7 @@ function setTimeout(after, value, options = {}) {
// to 12.x, then this can be converted to use optional chaining to
// simplify the check.
if (signal && signal.aborted) {
return PromiseReject(new AbortError());
return PromiseReject(new AbortError(undefined, { cause: signal.reason }));
}
let oncancel;
const ret = new Promise((resolve, reject) => {
@ -66,7 +66,7 @@ function setTimeout(after, value, options = {}) {
if (signal) {
oncancel = FunctionPrototypeBind(cancelListenerHandler,
// eslint-disable-next-line no-undef
timeout, clearTimeout, reject);
timeout, clearTimeout, reject, signal);
signal.addEventListener('abort', oncancel);
}
});
@ -101,7 +101,7 @@ function setImmediate(value, options = {}) {
// to 12.x, then this can be converted to use optional chaining to
// simplify the check.
if (signal && signal.aborted) {
return PromiseReject(new AbortError());
return PromiseReject(new AbortError(undefined, { cause: signal.reason }));
}
let oncancel;
const ret = new Promise((resolve, reject) => {
@ -110,7 +110,8 @@ function setImmediate(value, options = {}) {
if (signal) {
oncancel = FunctionPrototypeBind(cancelListenerHandler,
// eslint-disable-next-line no-undef
immediate, clearImmediate, reject);
immediate, clearImmediate, reject,
signal);
signal.addEventListener('abort', oncancel);
}
});
@ -127,7 +128,7 @@ async function* setInterval(after, value, options = {}) {
validateBoolean(ref, 'options.ref');
if (signal?.aborted)
throw new AbortError();
throw new AbortError(undefined, { cause: signal?.reason });
let onCancel;
let interval;
@ -147,7 +148,9 @@ async function* setInterval(after, value, options = {}) {
// eslint-disable-next-line no-undef
clearInterval(interval);
if (callback) {
callback(PromiseReject(new AbortError()));
callback(
PromiseReject(
new AbortError(undefined, { cause: signal.reason })));
callback = undefined;
}
};
@ -162,7 +165,7 @@ async function* setInterval(after, value, options = {}) {
yield value;
}
}
throw new AbortError();
throw new AbortError(undefined, { cause: signal?.reason });
} finally {
// eslint-disable-next-line no-undef
clearInterval(interval);

View File

@ -97,3 +97,10 @@ process.on('multipleResolves', common.mustNotCall());
assert.strictEqual(stderr, '');
}));
}
(async () => {
const signal = AbortSignal.abort('boom');
await assert.rejects(timerPromises.setImmediate(undefined, { signal }), {
cause: 'boom',
});
})().then(common.mustCall());

View File

@ -246,3 +246,15 @@ process.on('multipleResolves', common.mustNotCall());
setPromiseTimeout(time_unit * 3).then(() => post = true),
]).then(common.mustCall());
}
(async () => {
const signal = AbortSignal.abort('boom');
try {
const iterable = timerPromises.setInterval(2, undefined, { signal });
// eslint-disable-next-line no-unused-vars
for await (const _ of iterable) {}
assert.fail('should have failed');
} catch (err) {
assert.strictEqual(err.cause, 'boom');
}
})().then(common.mustCall());

View File

@ -97,3 +97,10 @@ process.on('multipleResolves', common.mustNotCall());
assert.strictEqual(stderr, '');
}));
}
(async () => {
const signal = AbortSignal.abort('boom');
await assert.rejects(timerPromises.setTimeout(1, undefined, { signal }), {
cause: 'boom',
});
})().then(common.mustCall());