Skip to content

Instantly share code, notes, and snippets.

@gustavomorinaga
Last active December 7, 2023 21:58
Show Gist options
  • Select an option

  • Save gustavomorinaga/ac4d6cc00a05feaa3c8c59ebc5afc7f8 to your computer and use it in GitHub Desktop.

Select an option

Save gustavomorinaga/ac4d6cc00a05feaa3c8c59ebc5afc7f8 to your computer and use it in GitHub Desktop.
This code efficiently handles asynchronous requests, measures their performance, structures responses for later processing or logging, and cancels network operations that time out.
/**
* Represents a request object.
*/
export type TRequest = {
id: number;
title: string;
url: string;
timeout: number;
};
/**
* Represents a response object.
*/
export type TResponse = {
response: any;
metadata: { status: number; elapsedTime: number };
};
/**
* Represents the names of performance marks.
*/
export type TMarkNames = {
start: `start-${string}`;
end: `end-${string}`;
duration: `duration-${string}`;
};
/**
* Clears the performance marks and measures for a given set of mark names.
* @param marks - The names of the performance marks.
*/
const clearElapsedPerformance = (marks: TMarkNames) => {
performance.clearMarks(marks.start);
performance.clearMarks(marks.end);
performance.clearMeasures(marks.duration);
};
/**
* Handles an array of requests asynchronously.
* @param requests - The array of requests to handle.
* @returns A promise that resolves to an array of fulfilled responses.
*/
const handleRequests = async (requests: Array<TRequest>) => {
const promises = requests.map(async (request): Promise<TResponse> => {
const signal = AbortSignal.timeout(request.timeout);
const markNames: TMarkNames = {
start: `start-${request.id}`,
end: `end-${request.id}`,
duration: `duration-${request.id}`,
};
let elapsedTime = 0;
performance.mark(markNames.start);
return fetch(request.url, { signal })
.finally(() => {
performance.mark(markNames.end);
performance.measure(markNames.duration, markNames.start, markNames.end);
const [{ duration }] = performance.getEntriesByName(
`duration-${request.id}`
);
elapsedTime = duration;
clearElapsedPerformance(markNames);
})
.then<TResponse>(async res => ({
metadata: { status: res.status, elapsedTime },
response: await res.json(),
}))
.catch<TResponse>(error => ({
metadata: { status: 408, elapsedTime },
response: error,
}));
});
return Promise.allSettled(promises)
.then(res => res.filter(({ status }) => status === 'fulfilled'))
.then(res =>
res.map(promise => (promise as PromiseFulfilledResult<TResponse>).value)
);
};
// Mock requests
const requests: Array<TRequest> = [
{
id: 1,
title: 'Rick and Morty',
url: 'https://rickandmortyapi.com/api/character/1',
timeout: 1000,
},
{
id: 2,
title: 'Amiibo',
url: 'https://amiiboapi.com/api/amiibo?name=mario',
timeout: 500,
},
];
// Handle requests
(async () => {
const results = await handleRequests(requests);
console.log(results);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment