Browse Source

Make `Lazy<T>` resolve atomically

master
buttercat1791 10 months ago
parent
commit
297be425d8
  1. 37
      src/lib/data_structures/lazy.ts

37
src/lib/data_structures/lazy.ts

@ -5,8 +5,9 @@ export enum LazyStatus {
} }
export class Lazy<T> { export class Lazy<T> {
#value?: T; #value: T | null = null;
#resolver: () => Promise<T>; #resolver: () => Promise<T>;
#pendingPromise: Promise<T | null> | null = null;
status: LazyStatus; status: LazyStatus;
@ -15,18 +16,40 @@ export class Lazy<T> {
this.status = LazyStatus.Pending; this.status = LazyStatus.Pending;
} }
async value(): Promise<T | null> { /**
if (!this.#value) { * Resolves the lazy object and returns the value.
*
* @returns The resolved value.
*
* @remarks Lazy object resolution is performed as an atomic operation. If a resolution has
* already been requested when this function is invoked, the pending promise from the earlier
* invocation is returned. Thus, all calls to this function before it is resolved will depend on
* a single resolution.
*/
value(): Promise<T | null> {
if (this.status === LazyStatus.Resolved) {
return Promise.resolve(this.#value);
}
if (this.#pendingPromise) {
return this.#pendingPromise;
}
this.#pendingPromise = this.#resolve();
return this.#pendingPromise;
}
async #resolve(): Promise<T | null> {
try { try {
this.#value = await this.#resolver(); this.#value = await this.#resolver();
this.status = LazyStatus.Resolved;
return this.#value;
} catch (error) { } catch (error) {
this.status = LazyStatus.Error; this.status = LazyStatus.Error;
console.error(error); console.error(error);
return null; return null;
} finally {
this.#pendingPromise = null;
} }
} }
this.status = LazyStatus.Resolved;
return this.#value;
}
} }
Loading…
Cancel
Save