Updating callback-style code to use async/await
Tags: javascript, tutorial, productivity
Published: 2020-06-07 18:05:11

# The problem
If you have been programming in Javascript for a while, you may have run into some code that looks like the following
```js
const example = (url, options) => {
  makeApiRequest((response, error) => { 
    if (error) console.log(error);
    console.log(response);
    // do something with response
  }, url, options);
};
```

This code uses a *callback* function to perform an *asynchronous* task.

The problem with writing asynchronous code like this is maintainability.
- Code written *below* the call to `makeApiRequest` is executed *before* the code written in the callback function
- Our additional arguments (`url` and `options`) appear *after* our callback function, which can be difficult to find
- If we need more asynchronous code within in our callback, we will end up further indented
- Error handling can become a total nightmare

In the olden days, this is how asynchronous code was written, and as a result of that, there are *many* libraries and methods that use callback functions like this, so it's fairly likely that you will run into async code using callback functions like this. 

However, since the formal adoption of [ES6](http://www.ecma-international.org/ecma-262/6.0/#sec-promise-objects), a better form of asynchronous code has become standardized: Promises. Promises allow us to write asynchronous code that is much more maintainable and easy to follow. If we could magically convert the above code to be Promise-based instead of using callbacks, it might look like this:
```js
const example = (url, options) => {
  makeApiRequest(url, options)
    .then((response) => {
      console.log(response);
      // do something with response
    })
    .catch((error) => console.log(error));
};
```

This solves *most* of our maintainability issues with callback functions, and can be made even better with the [Async/Await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) syntactic sugar standardized in ES8. 

Using this syntax on our magically Promisified `makeApiRequest` method would look like this:
```js
const example = async (url, options) => {
  try {
    const response = await makeApiRequest(url, options);
    console.log(response);
    // do something with response
  } catch (error) {
    console.log(error);
  }
};
```

Using `async` and `await` allows us to write code that *looks* synchronous, but actually performs asynchronous operations. Additionally, it prevents us from accidentally writing code that will happen before our async operation completes, and if we need to add more asynchronous code, we can write all of it in the same `try` block, making error handling *much* simpler.

Hooray! If only we could magically 'promisify' our old callback method...

# The Solution
I am borrowing the term 'promisify' from the [Node.js method](https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original) that does just that. How does it work? By simply wrapping our old function within a Promise!
```js
const response = await new Promise((resolve, reject) => {
  makeApiRequest((response, error) => {
    if (error) reject(error);
    resolve(response);
  }, url, options);
};
```

We can further improve this by making our own version of Node's `promisify` function:
```js
const promisify = (oldFunction) => {
  return ((...args) => (
    new Promise((resolve, reject) => {
      oldFunction((response, error) => {
        if (error) reject(error);
        resolve(response);
      }, ...args);
    });
  ));
}

const makeApiRequestWithPromise = promisify(makeApiReqeust);
```

Just be aware that our `promisify` method is dependent on the order of arguments supplied by our `makeApiRequest` method. Due to that reason, I tend to avoid using a `promisify` method, and instead just inline the Promise code.

Finally, if you are promisifying a function that does not ever return an error, you can shorten this trick like so:
```js
const example = async () => {
  console.log('3..2..1');
  await new Promise((resolve) => setTimeout(resolve, 1000));
  console.log('Go!');
}
```