18d307f52SEvan Bacon/** `lodash.memoize` */ 28d307f52SEvan Baconexport function memoize<T extends (...args: any[]) => any>(fn: T): T { 38d307f52SEvan Bacon const cache: { [key: string]: any } = {}; 48d307f52SEvan Bacon return ((...args: any[]) => { 58d307f52SEvan Bacon const key = JSON.stringify(args); 68d307f52SEvan Bacon if (cache[key]) { 78d307f52SEvan Bacon return cache[key]; 88d307f52SEvan Bacon } 98d307f52SEvan Bacon const result = fn(...args); 108d307f52SEvan Bacon cache[key] = result; 118d307f52SEvan Bacon return result; 128d307f52SEvan Bacon }) as any; 138d307f52SEvan Bacon} 14*d187cc4cSEvan Bacon 15*d187cc4cSEvan Bacon/** memoizes an async function to prevent subsequent calls that might be invoked before the function has finished resolving. */ 16*d187cc4cSEvan Baconexport function guardAsync<V, T extends (...args: any[]) => Promise<V>>(fn: T): T { 17*d187cc4cSEvan Bacon let invoked = false; 18*d187cc4cSEvan Bacon let returnValue: V; 19*d187cc4cSEvan Bacon 20*d187cc4cSEvan Bacon const guard: any = async (...args: any[]): Promise<V> => { 21*d187cc4cSEvan Bacon if (!invoked) { 22*d187cc4cSEvan Bacon invoked = true; 23*d187cc4cSEvan Bacon returnValue = await fn(...args); 24*d187cc4cSEvan Bacon } 25*d187cc4cSEvan Bacon 26*d187cc4cSEvan Bacon return returnValue; 27*d187cc4cSEvan Bacon }; 28*d187cc4cSEvan Bacon 29*d187cc4cSEvan Bacon return guard; 30*d187cc4cSEvan Bacon} 31