Skip to content

Instantly share code, notes, and snippets.

@Phoenix35
Last active April 6, 2019 02:37
Show Gist options
  • Save Phoenix35/0699bb303fe868129ab24a0d7d310e65 to your computer and use it in GitHub Desktop.
Save Phoenix35/0699bb303fe868129ab24a0d7d310e65 to your computer and use it in GitHub Desktop.
Small utility function to delay async operations
/**
* prepareAsync - Wraps an asynchronous function to be called several times with a delay between each call.
* @param {AsyncFunction} cb - The callback to wait for
* @param {number} delay - The delay (in milliseconds) between each call
* @param {Function} onFulfill - Function called after each success
* @param {Function} onError - Function to handle errors thrown during the resolutions of `cb` AND `onFulfill`
* @return {AsyncIterable}
*/
export default function prepareAsync (cb, delay, onFulfill, onError) {
const sleep = { then (resolve) {
setTimeout(resolve, delay);
} };
/**
* produceAsync - Asynchronously yields the result of the callback applied on each element of the iterable
* and wait a defined amount of time before the next call.
* @param {Iterable} it - The iterable to consume
* @param {?Object} thisArg - The optional `this` to pass to each call
* @param {?Function} done - Function to execute once the iterable is consumed
* @return {*} - The return value of `done`
*/
return async function *produceAsync (it, thisArg, done = () => {}) {
for (const x of it) {
yield await Reflect.apply(cb, thisArg, x)
.then(onFulfill)
.catch(onError);
await sleep;
}
return done();
};
}
// The whole thing can be seen as a transform stream with delay
/*
Example with fetch
*/
function fetchSuccess (response) {
if (!response.ok)
throw new TypeError(
`URL: ${response.url} ${response.status}: ${response.statusText}`
);
const cType = response.headers.get("Content-Type");
const method = cType.startsWith("application/json")
? "json"
: cType.startsWith("text/")
? "text"
: "arraybuffer";
return response[method]();
}
function fetchError (err) {
console.error(err);
}
const noSpamFetches = prepareAsync(
fetch,
2000, // Remember, delay is in ms!
fetchSuccess,
fetchError,
);
const baseURL = "https://jsonplaceholder.typicode.com/users/1";
const headers = {
Accept: "application/json",
};
// `.apply` expects an array-like object, i.e. `fetch.apply(null, [url, init])`
const userAlbumsRequest = [ `${baseURL}/albums`, { headers } ];
const userTodosRequest = [ `${baseURL}/todos`, { headers } ];
const userFailRequest = [ `${baseURL}/fa1l`, { headers } ];
const userPostsRequest = [ `${baseURL}/posts`, { headers } ];
// This is just to show it accepts any iterable
const userRequests = new Set([ userAlbumsRequest, userTodosRequest, userFailRequest, userPostsRequest ]);
const aggregatedResults = [];
for await (const result of noSpamFetches(
userRequests,
null,
() => console.log("I is done!"),
))
aggregatedResults.push(result);
// This is just to be clear that order is preserved
const [ userAlbums, userTodos, fetchErrorReturnsUndefined, userPosts ] = aggregatedResults;
console.log(userAlbums, userTodos, fetchErrorReturnsUndefined, userPosts);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment