From 9b7ecd08c9ea95a2ce510c947d65bc70cec52110 Mon Sep 17 00:00:00 2001 From: Alisue Date: Tue, 20 Aug 2024 13:17:16 +0900 Subject: [PATCH] feat(promiseState): add `immediate` option to skip wait Close #37 --- promise_state.ts | 22 ++++++++++++++++------ promise_state_bench.ts | 28 ++++++++++++++++++++++++++++ promise_state_test.ts | 13 +++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/promise_state.ts b/promise_state.ts index 4be0408..6e5ba89 100644 --- a/promise_state.ts +++ b/promise_state.ts @@ -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 * @@ -15,12 +24,13 @@ export type PromiseState = "fulfilled" | "rejected" | "pending"; * assertEquals(await promiseState(new Promise(() => {})), "pending"); * ``` */ -export async function promiseState(p: Promise): Promise { - // NOTE: - // This 0 delay promise is required to refresh internal states of promises - await new Promise((resolve) => { - setTimeout(() => resolve(), 0); - }); +export async function promiseState( + p: Promise, + { immediate }: PromiseStateOptions = {}, +): Promise { + if (!immediate) { + await flushPromises(); + } const t = {}; return Promise.race([p, t]).then( (v) => (v === t ? "pending" : "fulfilled"), diff --git a/promise_state_bench.ts b/promise_state_bench.ts index 8020e40..8c34926 100644 --- a/promise_state_bench.ts +++ b/promise_state_bench.ts @@ -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 () => { @@ -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 () => { @@ -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 () => { diff --git a/promise_state_test.ts b/promise_state_test.ts index ec20ee9..c5d7be7 100644 --- a/promise_state_test.ts +++ b/promise_state_test.ts @@ -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( @@ -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(); + 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"); +});