From 7abc67b456c4def29789b131696d0fe8757b92de Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 12 Mar 2023 21:35:03 +0200 Subject: [PATCH] Create providers/decorators.js --- providers/decorators.js | 113 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 providers/decorators.js diff --git a/providers/decorators.js b/providers/decorators.js new file mode 100644 index 00000000..63ba22cb --- /dev/null +++ b/providers/decorators.js @@ -0,0 +1,113 @@ +module.exports = { + singleton, + debounce, + cache, + throttle, + memoize, + retry, +}; + +/** + * @template T + * @param {T} fn + * @returns {T} + */ +function singleton(fn) { + let called = false; + return (...args) => { + if (called) return; + called = true; + return fn(...args); + }; +} + +/** + * @template T + * @param {T} fn + * @param {number} delay + * @returns {T} + */ +function debounce(fn, delay) { + let timeout; + return (...args) => { + clearTimeout(timeout); + timeout = setTimeout(() => fn(...args), delay); + }; +} + +/** + * @template T + * @param {T} fn + * @returns {T} + */ +function cache(fn) { + let lastArgs; + let lastResult; + return (...args) => { + if ( + args.length !== lastArgs?.length || + args.some((arg, i) => arg !== lastArgs[i]) + ) { + lastArgs = args; + lastResult = fn(...args); + } + return lastResult; + }; +} + +/* + the following are currently unused, but potentially useful in the future +*/ + +/** + * @template T + * @param {T} fn + * @param {number} delay + * @returns {T} + */ +function throttle(fn, delay) { + let timeout; + return (...args) => { + if (timeout) return; + timeout = setTimeout(() => { + timeout = undefined; + fn(...args); + }, delay); + }; +} + +/** + * @template T + * @param {T} fn + * @returns {T} + */ +function memoize(fn) { + const cache = new Map(); + return (...args) => { + const key = JSON.stringify(args); + if (!cache.has(key)) { + cache.set(key, fn(...args)); + } + return cache.get(key); + }; +} + +/** + * @template T + * @param {T} fn + * @returns {T} + */ +function retry(fn, { retries = 3, delay = 1000 } = {}) { + return (...args) => { + try { + return fn(...args); + } catch (e) { + if (retries > 0) { + retries--; + setTimeout(() => retry(fn, { retries, delay })(...args), delay); + } else { + throw e; + } + } + }; +}