Practical Async JavaScript
Tags: javascript, webdev, tutorial, learning
Published: 2024-05-23 17:18:01

## 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:

```javascript
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:

```javascript
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:

```javascript
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:
```javascript
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:


```javascript
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! 👋