Browse Source

Make `Lazy<T>` resolve atomically

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

47
src/lib/data_structures/lazy.ts

@ -5,8 +5,9 @@ export enum LazyStatus { @@ -5,8 +5,9 @@ export enum LazyStatus {
}
export class Lazy<T> {
#value?: T;
#value: T | null = null;
#resolver: () => Promise<T>;
#pendingPromise: Promise<T | null> | null = null;
status: LazyStatus;
@ -15,18 +16,40 @@ export class Lazy<T> { @@ -15,18 +16,40 @@ export class Lazy<T> {
this.status = LazyStatus.Pending;
}
async value(): Promise<T | null> {
if (!this.#value) {
try {
this.#value = await this.#resolver();
} catch (error) {
this.status = LazyStatus.Error;
console.error(error);
return null;
}
/**
* 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);
}
this.status = LazyStatus.Resolved;
return this.#value;
if (this.#pendingPromise) {
return this.#pendingPromise;
}
this.#pendingPromise = this.#resolve();
return this.#pendingPromise;
}
async #resolve(): Promise<T | null> {
try {
this.#value = await this.#resolver();
this.status = LazyStatus.Resolved;
return this.#value;
} catch (error) {
this.status = LazyStatus.Error;
console.error(error);
return null;
} finally {
this.#pendingPromise = null;
}
}
}
Loading…
Cancel
Save