Last active
September 18, 2019 07:50
-
-
Save pie6k/213b65b4c7ae1dfc09f56da2445b5252 to your computer and use it in GitHub Desktop.
Suspensify Promise Typescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type AllowedArg = number | string | boolean | null | undefined; | |
function stringifyArg(arg: AllowedArg) { | |
return `${arg}`; | |
} | |
function serializeArgs(args: AllowedArg[]) { | |
const argsLimiter = "<<<<***>>>>"; | |
if (args.length === 0) { | |
return "_"; | |
} | |
if (args.length === 1) { | |
return args[0].toString() + argsLimiter; | |
} | |
return args.map(stringifyArg).join(argsLimiter); | |
} | |
function suspendifyPromise<T, A extends AllowedArg[]>( | |
promiseGetter: (...args: A) => Promise<T>, | |
): (...args: A) => T { | |
// cache that will keep results for provided arguments | |
const cache: { [argsKey: string]: T | Promise<T> } = {}; | |
return function getSuspended(...args: A) { | |
// prepare cache key for given args | |
const argsKey = serializeArgs(args); | |
const cacheValue = cache[argsKey]; | |
// we have cache! it was called before with the same arguments (but it might be not resolved yet) | |
if (cacheValue !== undefined) { | |
// if value in cache is still promise | |
if (cacheValue instanceof Promise) { | |
// throw it to suspend | |
throw cacheValue; | |
} | |
// cache value is resolved - just return it | |
return cacheValue; | |
} | |
// get promise, but dont wait for it to resolve | |
const promise = promiseGetter(...args); | |
// save promise to cache to avoid creating promise again if it's requested again before it's resolved | |
cache[argsKey] = promise; | |
// wait for promise to resolve and then add resolved value to cache | |
promise.then(result => { | |
cache[argsKey] = result; | |
}); | |
// suspense with promise of value | |
throw promise; | |
}; | |
} | |
const getHello = suspendifyPromise( | |
(id: string) => | |
new Promise<string>(resolve => { | |
resolve(`Hello, ${id}`); | |
}), | |
); | |
// getHello("Bob") -> "Hello, Bob" or throw |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment