Created
July 18, 2020 14:54
-
-
Save StevenLangbroek/cb387dee1cb79f144e819813ae639a1e to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// lil' helpers for squeaky clean code 😎 | |
const load = (url: string) => | |
fetch(url).then(async r => { | |
const json = await r.json(); | |
if (!r.ok) { | |
throw json; | |
} | |
return json; | |
}); | |
const all = Promise.all.bind(Promise); | |
type LoadManyMode = "sequential" | "parallel"; | |
/** | |
* This might need a little bit of explanation depending on how much | |
* you keep up to date with TC39 proposals etc. Let's get the simple stuff | |
* out of the way first. If you have a function to load a single element, | |
* you pass it to `loadMany` and get a function back that, given an array | |
* of whatever you ask for the element by (e.g., a uuid, slug or numeric id), | |
* will load those one-by-one, as fast as it can. | |
* | |
* You can tell it to either load all items in sequence, or in parallel. | |
* | |
* It does that by leveraging an Async Generator function. It's a generator function, | |
* so it can yield multiple values, and since it's async you can `await` elements | |
* inside of it. Async Generators implement the AsyncIterator interface, which means | |
* you can iterate over it using `for await (const el of asyncIterator)`. For more details, | |
* as always MDN has the goods: | |
* | |
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of | |
* @param loader Promise-returning function to get a single element | |
*/ | |
interface ManyLoader<T> { | |
(elements: any[], mode: "sequential"): AsyncGenerator<T>; | |
(elements: any[], mode: "parallel"): AsyncGenerator<T[]>; | |
} | |
export const loadMany = <T extends unknown>( | |
loader: (element: any) => Promise<T> | |
): ManyLoader<T> => { | |
return async function*(elements: any[], mode: LoadManyMode = "sequential") { | |
if (mode === "parallel") { | |
yield await all(elements.map(loader)); | |
return; | |
} | |
for (const el of elements) { | |
yield await loader(el); | |
} | |
}; | |
}; | |
const loadItem = (id: number) => load(`/api/item?id=${id}`); | |
const loadItems = loadMany<Item>(loadItem); | |
// use: | |
loadItems(ids, 'parallel') | |
loadItems(ids, 'sequential') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment