Last active
December 7, 2023 21:58
-
-
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.
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
| /** | |
| * 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