Practical Async JavaScript
Bogdan Varlamov
Posted on May 23, 2024
Introduction
Let's take a moment to brush up on some JavaScript async concepts together.
What is Asynchronous?
First off, let's remind ourselves what an asynchronous process is. Simply put, it's a process that doesn't execute immediately but has a delay or lag. It's like ordering a coffee at a busy café - you place your order, and it takes a bit of time before you get your cup.
Creating a Fake API Call
Alright, can we create a function that mimics a basic API call?
Absolutely! Here's a simple example:
function fakeApiCall(response) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`Success: ${response}`);
}, 1000);
});
}
Our fakeApiCall function takes a value and returns it after a 1-second delay, labeled with "Success." We're using a Promise because it always handles asynchronous code, and setTimeout to manage the delay.
Adding Error Handling
But hey, do API calls always return the expected value? Nope, sometimes they return errors. Let's add this functionality too:
function fakeApiCall(response) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve(`Success: ${response}`);
} else {
reject('API call failed: try again');
}
}, 1000);
});
}
Here, we've added a condition using Math.random(). Now, there's a 50% chance of success and a 50% chance of failure, mimicking real-world API behavior.
Retrying on Failure
Great! But what if we want to retry the API call when it fails? Let's tackle that:
let attempt = 0;
async function makeApiCallWithRetries(value) {
try {
const result = await fakeApiCall(value);
return result;
} catch (error) {
attempt++;
console.log(`Attempt ${attempt} failed: ${error} - for value: ${value}`);
return makeApiCallWithRetries(value);
}
}
In this code, we retry until we get a successful response.
Note, this could lead to an infinite loop if we're unlucky, but we'll hope for the best!
Setting a Retry Limit
To avoid that infinite loop, let's set a maximum retry limit:
let attempt = 0;
const maxRetries = 5;
async function makeApiCallWithRetries(value) {
try {
const result = await fakeApiCall(value);
return result;
} catch (error) {
attempt++;
if (attempt >= maxRetries) {
throw new Error(`Max retries reached: ${error}`);
}
console.log(`Attempt ${attempt} failed: ${error} - for value: ${value}`);
return makeApiCallWithRetries(value);
}
}
Now, we'll stop trying after five attempts, avoiding the dreaded infinite loop.
Making Parallel API Calls
So, what if we need to make multiple API calls simultaneously?
Let's think this through. Imagine we have a bunch of requests that need to go out all at once. How can we handle that efficiently?
Well, we can run them in parallel. Here's how:
async function makeApiCallsInParallel(values) {
const promises = values.map((value) => makeApiCallWithRetries(value));
const results = await Promise.allSettled(promises);
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Response ${index + 1} succeeded: ${result.value}`);
} else {
console.log(`Response ${index + 1} failed: ${result.reason}`);
}
});
}
This function takes an array of values and calls makeApiCallWithRetries for each value in parallel. We're using Promise.allSettled to handle both successful and failed calls.
Conclusion
I hope this refreshed your memory about core JavaScript async functionality or even taught you something new.
Thanks for hanging out! Hit subscribe for more! 👋
Posted on May 23, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
July 6, 2024