Ignoring superseded function calls
Below is a generic typed function that can wrap another async function and reject any superseded calls.
You pass it your async function and get back a new function with the same signature, but if it’s been called subsequently it will throw an error (i.e. the promise is rejected).
This is useful if, for example, you’re fetching new results to user input on each keystroke but want to ensure that, if the results return out of order, displayed results are shown only from the most recent call.
export const latest = <A extends Array<unknown>, T>(fn: (...args: A) => Promise<T>) => {
let invocationId: object;
return async (...args: A) => {
const thisInvocationId = (invocationId = new Object());
const result = await fn(...args);
if (invocationId !== thisInvocationId) {
throw new Error('Function invocation superseded', { cause: 'SUPERSEDED' });
}
return result;
};
};
Here’s an example usage:
const fetchResults = async (url) => {
return fetch(url);
};
const fetchLatestResults = latest(fetchResults);
const handleResults = (restuls) => {
// update some UI with the new results.
};
const handleError = (err) => {
if (err.cause === 'SUPERSEDED') {
// ignore this
return;
}
// handle an actual error
};
// For some reason this first call takes ages
fetchLatestResults('https://example.com/api.json').then(handleResults).then(handleError);
// For some reason this second call returns quickly
fetchLatestResults('https://example.com/api.json').then(handleResults).then(handleError);