Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion async/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"./unstable-wait-for": "./unstable_wait_for.ts",
"./unstable-semaphore": "./unstable_semaphore.ts",
"./unstable-circuit-breaker": "./unstable_circuit_breaker.ts",
"./unstable-lazy": "./unstable_lazy.ts",
"./lazy": "./lazy.ts",
"./unstable-pool-settled": "./unstable_pool_settled.ts",
"./unstable-channel": "./unstable_channel.ts"
}
Expand Down
30 changes: 8 additions & 22 deletions async/unstable_lazy.ts → async/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

/**
* Options for {@linkcode Lazy.prototype.get}.
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*/
export interface LazyGetOptions {
/**
Expand All @@ -31,7 +29,7 @@ export interface LazyGetOptions {
* @example Concurrent deduplication
*
* ```ts
* import { Lazy } from "@std/async/unstable-lazy";
* import { Lazy } from "@std/async/lazy";
* import { assertEquals } from "@std/assert";
*
* let initCount = 0;
Expand All @@ -49,7 +47,7 @@ export interface LazyGetOptions {
* @example Composing with retry
*
* ```ts ignore
* import { Lazy } from "@std/async/unstable-lazy";
* import { Lazy } from "@std/async/lazy";
* import { retry } from "@std/async/retry";
*
* const db = new Lazy(() =>
Expand All @@ -58,8 +56,6 @@ export interface LazyGetOptions {
* await db.get();
* ```
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*
* @typeParam T The type of the lazily initialized value.
*/
export class Lazy<T> {
Expand All @@ -71,8 +67,6 @@ export class Lazy<T> {
/**
* Creates a new lazy value.
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*
* @param init Initializer function, called at most once (until {@linkcode reset}).
*/
constructor(init: () => T | Promise<T>) {
Expand All @@ -88,15 +82,15 @@ export class Lazy<T> {
*
* @example Usage
* ```ts no-assert
* import { Lazy } from "@std/async/unstable-lazy";
* import { Lazy } from "@std/async/lazy";
*
* const config = new Lazy(async () => ({ loaded: true }));
* const value = await config.get();
* ```
*
* @example Abort a slow initialization
* ```ts
* import { Lazy } from "@std/async/unstable-lazy";
* import { Lazy } from "@std/async/lazy";
* import { assertRejects } from "@std/assert";
*
* const slow = new Lazy(() => new Promise<string>(() => {}));
Expand All @@ -109,8 +103,6 @@ export class Lazy<T> {
* );
* ```
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*
* @param options Optional settings for this call.
* @returns The cached or newly initialized value.
*/
Expand Down Expand Up @@ -163,7 +155,7 @@ export class Lazy<T> {
*
* @example Check initialization state
* ```ts
* import { Lazy } from "@std/async/unstable-lazy";
* import { Lazy } from "@std/async/lazy";
* import { assertEquals } from "@std/assert";
*
* const lazy = new Lazy(() => 42);
Expand All @@ -172,8 +164,6 @@ export class Lazy<T> {
* assertEquals(lazy.initialized, true);
* ```
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*
* @returns `true` if the value has been initialized, `false` otherwise.
*/
get initialized(): boolean {
Expand All @@ -187,7 +177,7 @@ export class Lazy<T> {
*
* @example Fast-path when already initialized
* ```ts
* import { Lazy } from "@std/async/unstable-lazy";
* import { Lazy } from "@std/async/lazy";
* import { assertEquals } from "@std/assert";
*
* const config = new Lazy(async () => ({ port: 8080 }));
Expand All @@ -199,15 +189,13 @@ export class Lazy<T> {
*
* @example Not yet initialized
* ```ts
* import { Lazy } from "@std/async/unstable-lazy";
* import { Lazy } from "@std/async/lazy";
* import { assertEquals } from "@std/assert";
*
* const lazy = new Lazy(() => 42);
* assertEquals(lazy.peek(), { ok: false });
* ```
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*
* @returns `{ ok: true, value }` if the value has been initialized, or
* `{ ok: false }` if not yet initialized or still in-flight.
*/
Expand All @@ -224,15 +212,13 @@ export class Lazy<T> {
*
* @example Force reload
* ```ts ignore
* import { Lazy } from "@std/async/unstable-lazy";
* import { Lazy } from "@std/async/lazy";
*
* const config = new Lazy(async () => loadConfig());
* await config.get();
* config.reset();
* const fresh = await config.get();
* ```
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*/
reset(): void {
this.#promise = undefined;
Expand Down
31 changes: 30 additions & 1 deletion async/unstable_lazy_test.ts → async/lazy_test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2018-2026 the Deno authors. MIT license.

import { assertEquals, assertRejects, assertStrictEquals } from "@std/assert";
import { Lazy } from "./unstable_lazy.ts";
import { Lazy } from "./lazy.ts";

Deno.test("Lazy.get() initializes and returns sync value", async () => {
const lazy = new Lazy(() => 42);
Expand Down Expand Up @@ -181,6 +181,35 @@ Deno.test("Lazy.reset() does not affect in-flight initialization", async () => {
assertEquals(value, "ok");
});

Deno.test("Lazy.get() after reset() during in-flight triggers fresh init", async () => {
let initCount = 0;
const holders: { resolve: (v: number) => void }[] = [];
const lazy = new Lazy<number>(
() =>
new Promise((res) => {
initCount++;
holders.push({ resolve: res });
}),
);

const first = lazy.get();
await Promise.resolve();
assertEquals(initCount, 1);

lazy.reset();
const second = lazy.get();
await Promise.resolve();
assertEquals(initCount, 2);

holders[0]!.resolve(1);
holders[1]!.resolve(2);

assertEquals(await first, 1);
assertEquals(await second, 2);
assertEquals(lazy.initialized, true);
assertEquals(lazy.peek(), { ok: true, value: 2 });
});

Deno.test("Lazy.get() resolves falsy values correctly", async (t) => {
await t.step("0", async () => {
const lazy = new Lazy(() => 0);
Expand Down
1 change: 1 addition & 0 deletions async/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export * from "./pool.ts";
export * from "./tee.ts";
export * from "./retry.ts";
export * from "./all_keyed.ts";
export * from "./lazy.ts";
Loading