Skip to content

Commit

Permalink
feat(promiseState): add immediate option to skip wait
Browse files Browse the repository at this point in the history
Close #37
  • Loading branch information
lambdalisue committed Aug 20, 2024
1 parent cd7a48b commit 9b7ecd0
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 6 deletions.
22 changes: 16 additions & 6 deletions promise_state.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { flushPromises } from "./flush_promises.ts";

/**
* Promise state
*/
export type PromiseState = "fulfilled" | "rejected" | "pending";

export type PromiseStateOptions = {
/**
* If true, the promise state is checked immediately without waiting for the next event loop.
*/
immediate?: boolean;
};

/**
* Return state (fulfilled/rejected/pending) of a promise
*
Expand All @@ -15,12 +24,13 @@ export type PromiseState = "fulfilled" | "rejected" | "pending";
* assertEquals(await promiseState(new Promise(() => {})), "pending");
* ```
*/
export async function promiseState(p: Promise<unknown>): Promise<PromiseState> {
// NOTE:
// This 0 delay promise is required to refresh internal states of promises
await new Promise<void>((resolve) => {
setTimeout(() => resolve(), 0);
});
export async function promiseState(
p: Promise<unknown>,
{ immediate }: PromiseStateOptions = {},
): Promise<PromiseState> {
if (!immediate) {
await flushPromises();
}
const t = {};
return Promise.race([p, t]).then(
(v) => (v === t ? "pending" : "fulfilled"),
Expand Down
28 changes: 28 additions & 0 deletions promise_state_bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ Deno.bench({
baseline: true,
});

Deno.bench({
name: "current (immediate)",
fn: async () => {
await promiseState(Promise.resolve("fulfilled"), { immediate: true });
},
group: "promiseState (fulfilled)",
baseline: true,
});

Deno.bench({
name: "v1.0.0",
fn: async () => {
Expand All @@ -31,6 +40,16 @@ Deno.bench({
baseline: true,
});

Deno.bench({
name: "current (immediate)",
fn: async () => {
const p = Promise.reject("reject").catch(() => {});
await promiseState(p, { immediate: true });
},
group: "promiseState (rejected)",
baseline: true,
});

Deno.bench({
name: "v1.0.0",
fn: async () => {
Expand All @@ -49,6 +68,15 @@ Deno.bench({
baseline: true,
});

Deno.bench({
name: "current (immediate)",
fn: async () => {
await promiseState(new Promise(() => {}), { immediate: true });
},
group: "promiseState (pending)",
baseline: true,
});

Deno.bench({
name: "v1.0.0",
fn: async () => {
Expand Down
13 changes: 13 additions & 0 deletions promise_state_test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { test } from "@cross/test";
import { assertEquals } from "@std/assert";
import { flushPromises } from "./flush_promises.ts";
import { promiseState } from "./promise_state.ts";

test(
Expand Down Expand Up @@ -36,3 +37,15 @@ test("promiseState() returns refreshed status", async () => {
resolve();
assertEquals(await promiseState(p), "fulfilled");
});

test("promiseState() returns unrefreshed status with { immediate: true }", async () => {
const { promise, resolve } = Promise.withResolvers<void>();
const p = (async () => {
await promise;
})();
assertEquals(await promiseState(p, { immediate: true }), "pending");
resolve();
assertEquals(await promiseState(p, { immediate: true }), "pending");
await flushPromises();
assertEquals(await promiseState(p, { immediate: true }), "fulfilled");
});

0 comments on commit 9b7ecd0

Please sign in to comment.