fix(async/delay): reject with existing AbortSignal reason (#3479)

This commit is contained in:
Jesse Jackson 2023-07-14 00:03:05 -05:00 committed by GitHub
parent 239e85ad6a
commit 82c63fc1f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 18 deletions

View File

@ -38,13 +38,11 @@ export interface DelayOptions {
*/
export function delay(ms: number, options: DelayOptions = {}): Promise<void> {
const { signal, persistent } = options;
if (signal?.aborted) {
return Promise.reject(new DOMException("Delay was aborted.", "AbortError"));
}
if (signal?.aborted) return Promise.reject(signal.reason);
return new Promise((resolve, reject) => {
const abort = () => {
clearTimeout(i);
reject(new DOMException("Delay was aborted.", "AbortError"));
reject(signal?.reason);
};
const done = () => {
signal?.removeEventListener("abort", abort);

View File

@ -1,6 +1,17 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { delay } from "./delay.ts";
import { assert, assertRejects } from "../assert/mod.ts";
import {
assert,
assertInstanceOf,
assertRejects,
assertStrictEquals,
} from "../assert/mod.ts";
// https://dom.spec.whatwg.org/#interface-AbortSignal
function assertIsDefaultAbortReason(reason: unknown) {
assertInstanceOf(reason, DOMException);
assertStrictEquals(reason.name, "AbortError");
}
Deno.test("[async] delay", async function () {
const start = new Date();
@ -17,14 +28,45 @@ Deno.test("[async] delay with abort", async function () {
const { signal } = abort;
const delayedPromise = delay(100, { signal });
setTimeout(() => abort.abort(), 0);
await assertRejects(
() => delayedPromise,
DOMException,
"Delay was aborted",
);
const cause = await assertRejects(() => delayedPromise);
const diff = new Date().getTime() - start.getTime();
assert(diff < 100);
assertIsDefaultAbortReason(cause);
});
Deno.test("[async] delay with abort reason", async function (ctx) {
async function assertRejectsReason(reason: unknown) {
const start = new Date();
const abort = new AbortController();
const { signal } = abort;
const delayedPromise = delay(100, { signal });
setTimeout(() => abort.abort(reason), 0);
const cause = await assertRejects(() => delayedPromise);
const diff = new Date().getTime() - start.getTime();
assert(diff < 100);
assertStrictEquals(cause, reason);
}
await ctx.step("not-undefined values", async () => {
await Promise.all([
null,
new Error("Timeout cancelled"),
new DOMException("Timeout cancelled", "AbortError"),
new DOMException("The signal has been aborted", "AbortError"),
].map(assertRejectsReason));
});
await ctx.step("undefined", async () => {
const start = new Date();
const abort = new AbortController();
const { signal } = abort;
const delayedPromise = delay(100, { signal });
setTimeout(() => abort.abort(), 0);
const cause = await assertRejects(() => delayedPromise);
const diff = new Date().getTime() - start.getTime();
assert(diff < 100);
assertIsDefaultAbortReason(cause);
});
});
Deno.test("[async] delay with non-aborted signal", async function () {
@ -32,7 +74,6 @@ Deno.test("[async] delay with non-aborted signal", async function () {
const abort = new AbortController();
const { signal } = abort;
const delayedPromise = delay(100, { signal });
// abort.abort()
const result = await delayedPromise;
const diff = new Date().getTime() - start.getTime();
assert(result === undefined);
@ -57,12 +98,8 @@ Deno.test("[async] delay with already aborted signal", async function () {
abort.abort();
const { signal } = abort;
const delayedPromise = delay(100, { signal });
await assertRejects(
() => delayedPromise,
DOMException,
"Delay was aborted",
);
const cause = await assertRejects(() => delayedPromise);
const diff = new Date().getTime() - start.getTime();
assert(diff < 100);
assertIsDefaultAbortReason(cause);
});