Asynchronous Javascript: 3 ways
Tags: javascript, beginners
Published: 2019-07-10 11:29:36

## Callbacks, Promises, and Async/Await

The JavaScript engine is single threaded and utilises an event loop. Simply put, this means any statements you run will be executed one after the other in a single process. To avoid blocking calls, there are a number of techniques that JavaScript employs to avoid waiting while something is computed. These are **asynchronous functions**.

You can read more about the event loop [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop) as the topic is too deep to cover in this post.

JavaScript provides three methods of handling asynchronous code: callbacks, which allow you to provide functions to call once the asynchronous method has finished running; promises, which allow you to chain methods together; and async/await keywords, which are just some syntactic sugar over promises.

### Callbacks

The original method of handling asynchronicity. Callbacks allow you to provide a function to be executed **after** the asynchronous code has finished. In the example below, `functionWithACallback` takes a function as an argument and will call that function when it is finished.

This method, passing functions back and forth, can become very confusing if you need to chain a number of these calls together. The callback will need to be passed down the execution chain to be called at the end of the final process.

```js
const functionWithACallback = (callback) => {
  //do some work then call the callback once done
  console.log('You called this function!');
  setTimeout(() => {
    callback('I am done');
  }, 1000)
};

const myFunction = () => {
  // the function we want to call when the work is done
  const myCallback = console.log
  // this will call myCallback once it is finished 
  functionWithACallback(myCallback);
};

myFunction();
//  You called this function
//  I am done
```

### Promises
One of the main problems with callbacks is, when chaining a number of function calls together it can become increasingly difficult to follow the flow of execution. Promises aim to solve this issue by allowing you to chain together promises using the `.then()` syntax. The example below works the same way as the callback example, but is much easier to follow: wait till `getPromise()` has completed and **then** call the function containing `console.log()`

Error handling with promises is also less complex. Rather than calling the callback with an error object, promises provide a `.catch()` wrapper to help manage error states. Below, the `catch` block will be executed if an error occurs in any of the promises above it.

```js
const getPromise = () => Promise.resolve('My return value');

const myFunction = () => {
  getPromise()
    .then(val => { 
      console.log(val); // prints 'My return value'
    }) // If there is an error in any of the above promises, catch
       // it here
    .catch(error => {   
      console.error(error.message);
    });
}
```

### Async/Await
In the more recent versions of JavaScript, the `async` and `await` keywords were added. This provides a cleaner method of writing promises and gives the user more control over execution order. The below example is identical to the promises example in functionality, but is written using the `async` and `await ` keywords.
Error handling for `async` function calls is provided using a `try/catch` block.

```js
const getPromise = () => Promise.resolve('My return value');
// the function is marked with the async keyword
const myFunction = async () => {  
  // tell the interpreter we want to wait on the response
  try {
    const val = await getPromise();
    // execute when the promise above is resolved
    console.log(val); // prints 'My return value'
  } catch (error) {
    console.error(error.message);
  }
}
```