Typescript CachedPromise

import { dateAdd } from "./DateHelpers";

export class CachedPromise<T> {
    private _dataPromise: PromiseLike<T> | undefined = undefined;
    private _dataDate: Date | undefined;
    constructor(private _dataFn: () => PromiseLike<T>, private _validMinutes: number = 20) { }
    async load(reload: boolean = false) {
        if (!this._dataPromise || reload || this.isExpired()) {
            this._dataDate = new Date();
            return this.reload();
        }
        return await this._dataPromise;
    }

    isExpired(): boolean {
        const expiryDate = dateAdd(new Date(), -1 * this._validMinutes * 60 * 1000);
        const isExpired = !this._dataDate || this._dataDate < expiryDate;
        return isExpired;
    }

    setExpired() {
        this._dataDate = undefined;
    }

    async reload() {
        this._dataPromise = this._dataFn();
        return await this._dataPromise;
    }
}

// usage:
const measurementsPromise = new CachedPromise<any>(() => restApiHelper.getData("api/measurements"), 10);

measurementsPromise.load();
measurementsPromise.load(); // cached
measurementsPromise.load(true); // not cached
measurementsPromise.reload(); // not cached

Auto refresh

export class AutoRefreshCachedPromise<T> {
    private _dataPromise: PromiseLike<T> | undefined;
    private _refreshTimer: ReturnType<typeof setInterval> | undefined;
    private _refreshInProgress = false;

    constructor(private _dataFn: () => PromiseLike<T>, private _refreshIntervalInMs: number) { }

    async load(reload: boolean = false) {
        this.startRefreshTimer();
        if (!this._dataPromise || reload) {
            return this.reload();
        }
        return await this._dataPromise;
    }

    async reload() {
        this._dataPromise = this._dataFn();
        return await this._dataPromise;
    }

    stopRefresh(): void {
        if (!this._refreshTimer) {
            return;
        }

        clearInterval(this._refreshTimer);
        this._refreshTimer = undefined;
    }

    private startRefreshTimer(): void {
        if (this._refreshTimer) {
            return;
        }

        this._refreshTimer = setInterval(() => {
            void this.refreshInBackground();
        }, this._refreshIntervalInMs);
    }

    private async refreshInBackground(): Promise<void> {
        if (this._refreshInProgress) {
            return;
        }

        this._refreshInProgress = true;
        try {
            await this.reload();
        } catch {
            // Optional background refresh errors are intentionally swallowed.
        } finally {
            this._refreshInProgress = false;
        }
    }
}
22070cookie-checkTypescript CachedPromise