UNPKG

scrivito

Version:

Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.

81 lines (71 loc) 2.88 kB
import { LoadableState, createLoadableData, isCurrentlyCapturing, } from 'scrivito_sdk/loadable'; import { dejitterStateStream } from 'scrivito_sdk/loadable/dejitter_state_stream'; import { observeAndLoad } from 'scrivito_sdk/loadable/observe_and_load'; import { createStateContainer } from 'scrivito_sdk/state'; interface FunctionState<T> { [serializedArgs: string]: LoadableState<T>; } /** Wrap the given function so that it uses a "loadable" cache. * * If the function is called with a loadable context (e.g. inside load or connect), * caching will automatically be used. * * Outside of a loadable context, the function will be called without caching, * i.e. as a normal JS function. * * Caching has several effects: * * The function is computed asynchronously ("in the background"). * * The function is cached, i.e. several consumers can use the function with * the same input, but only one computation takes place for each unique input. * * Once completely loaded, the function does not "jitter", * i.e. no temporary incomplete results are shown. * * While the function is loading, the 'defaultValue' is returned. * * If the function has parameters, an 'argsToString' function must be provided, * which maps each unique input to a unique string (which is used as the cache key). * * It is recommended to use primitive parameters, e.g. an obj ID instead of a `BasicObj` instance. */ export function loadableFunction<Args extends unknown[], Return>( defaultValue: Return, argsToString: (...args: Args) => string, fn: (...args: Args) => Return ): (...args: Args) => Return; export function loadableFunction<Return>( defaultValue: Return, zeroArgsFn?: () => Return ): () => Return; export function loadableFunction<Args extends unknown[], Return>( defaultValue: Return, argsToStringOrZeroArgsFn: | ((...args: Args) => string) | ((...args: Args) => Return), fn?: (...args: Args) => Return ): (...args: Args) => Return { if (!fn) { const zeroArgsFn = argsToStringOrZeroArgsFn as (...args: Args) => Return; return createLoadableFunction(defaultValue, () => '', zeroArgsFn); } const argsToString = argsToStringOrZeroArgsFn as (...args: Args) => string; return createLoadableFunction(defaultValue, argsToString, fn); } function createLoadableFunction<Args extends unknown[], Return>( defaultValue: Return, argsToString: (...args: Args) => string, fn: (...args: Args) => Return ): (...args: Args) => Return { const functionState = createStateContainer<FunctionState<Return>>(); return (...args: Args) => { if (!isCurrentlyCapturing()) return fn(...args); const data = createLoadableData({ state: functionState.subState(argsToString(...args)), loadableStream: dejitterStateStream(observeAndLoad(() => fn(...args))), }); return data.getWithDefault(defaultValue); }; }