mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
feat(async): support signal
on deadline()
(#3347)
This commit is contained in:
parent
c5dbe0747b
commit
264c7144b1
@ -1,12 +1,17 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
import { deferred } from "./deferred.ts";
|
||||
import { delay } from "./delay.ts";
|
||||
|
||||
export interface DeadlineOptions {
|
||||
/** Signal used to abort the deadline. */
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
export class DeadlineError extends Error {
|
||||
constructor() {
|
||||
super("Deadline");
|
||||
this.name = "DeadlineError";
|
||||
this.name = this.constructor.name;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,8 +30,19 @@ export class DeadlineError extends Error {
|
||||
* const result = await deadline(delayedPromise, 10);
|
||||
* ```
|
||||
*/
|
||||
export function deadline<T>(p: Promise<T>, delay: number): Promise<T> {
|
||||
const d = deferred<never>();
|
||||
const t = setTimeout(() => d.reject(new DeadlineError()), delay);
|
||||
return Promise.race([p, d]).finally(() => clearTimeout(t));
|
||||
export function deadline<T>(
|
||||
p: Promise<T>,
|
||||
ms: number,
|
||||
options: DeadlineOptions = {},
|
||||
): Promise<T> {
|
||||
const controller = new AbortController();
|
||||
const { signal } = options;
|
||||
if (signal?.aborted) {
|
||||
return Promise.reject(new DeadlineError());
|
||||
}
|
||||
signal?.addEventListener("abort", () => controller.abort(signal.reason));
|
||||
const d = delay(ms, { signal: controller.signal })
|
||||
.catch(() => {}) // Do NOTHING on abort.
|
||||
.then(() => Promise.reject(new DeadlineError()));
|
||||
return Promise.race([p.finally(() => controller.abort()), d]);
|
||||
}
|
||||
|
@ -1,28 +1,37 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertRejects } from "../testing/asserts.ts";
|
||||
import { deferred } from "./deferred.ts";
|
||||
import { delay } from "./delay.ts";
|
||||
import { deadline, DeadlineError } from "./deadline.ts";
|
||||
|
||||
Deno.test("[async] deadline: return fulfilled promise", async () => {
|
||||
const p = deferred();
|
||||
const t = setTimeout(() => p.resolve("Hello"), 100);
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
const p = delay(100, { signal })
|
||||
.catch(() => {})
|
||||
.then(() => "Hello");
|
||||
const result = await deadline(p, 1000);
|
||||
assertEquals(result, "Hello");
|
||||
clearTimeout(t);
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
Deno.test("[async] deadline: throws DeadlineError", async () => {
|
||||
const p = deferred();
|
||||
const t = setTimeout(() => p.resolve("Hello"), 1000);
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
const p = delay(1000, { signal })
|
||||
.catch(() => {})
|
||||
.then(() => "Hello");
|
||||
await assertRejects(async () => {
|
||||
await deadline(p, 100);
|
||||
}, DeadlineError);
|
||||
clearTimeout(t);
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
Deno.test("[async] deadline: thrown when promise is rejected", async () => {
|
||||
const p = deferred();
|
||||
const t = setTimeout(() => p.reject(new Error("booom")), 100);
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
const p = delay(100, { signal })
|
||||
.catch(() => {})
|
||||
.then(() => Promise.reject(new Error("booom")));
|
||||
await assertRejects(
|
||||
async () => {
|
||||
await deadline(p, 1000);
|
||||
@ -30,5 +39,46 @@ Deno.test("[async] deadline: thrown when promise is rejected", async () => {
|
||||
Error,
|
||||
"booom",
|
||||
);
|
||||
clearTimeout(t);
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
Deno.test("[async] deadline: with non-aborted signal", async () => {
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
const p = delay(100, { signal })
|
||||
.catch(() => {})
|
||||
.then(() => "Hello");
|
||||
const abort = new AbortController();
|
||||
const result = await deadline(p, 1000, { signal: abort.signal });
|
||||
assertEquals(result, "Hello");
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
Deno.test("[async] deadline: with signal aborted after delay", async () => {
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
const p = delay(100, { signal })
|
||||
.catch(() => {})
|
||||
.then(() => "Hello");
|
||||
const abort = new AbortController();
|
||||
const promise = deadline(p, 100, { signal: abort.signal });
|
||||
abort.abort();
|
||||
await assertRejects(async () => {
|
||||
await promise;
|
||||
}, DeadlineError);
|
||||
controller.abort();
|
||||
});
|
||||
|
||||
Deno.test("[async] deadline: with already aborted signal", async () => {
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
const p = delay(100, { signal })
|
||||
.catch(() => {})
|
||||
.then(() => "Hello");
|
||||
const abort = new AbortController();
|
||||
abort.abort();
|
||||
await assertRejects(async () => {
|
||||
await deadline(p, 100, { signal: abort.signal });
|
||||
}, DeadlineError);
|
||||
controller.abort();
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user