By Ken Howard on 6/16/2017

Have Questions?

Call us at 503-292-0859 or fill out our contact form. We'd love to talk with you.

JavaScript developers have suffered long enough. The wait for asynchronous functions is over. Here's what you need to know to use the new feature today.

Really Good Browser Support

Async/Await Browser Availability

While not all browsers support Async/Await (async functions), current versions of major browsers are ready for your next generation JavaScript.

But, If you are in need of supporting old browsers (like most of us) rest assured there's a way to use this feature without breaking the web. Keep reading and I'll show you how to use Async/Await while supporting older browsers.

Why Use Async/Await?

For a really, really long time, JavaScript suffered from callback hell.

Asynchronous JavaScript, or JavaScript that uses callbacks, is hard to get right intuitively.

doSomething(1, function (2) {
  function (3, function (4) {
    function (5, function (6) {
      console.log('Where am I?');
    });
  });
});

In the recent past, we were blessed with the introduction of the Promise. A Promise provides a way to chain asynchronous functions together and avoid nested functions (callbacks).

// Create the promise
function myPromiseFn (val) {
  return new Promise(function (resolve, reject) {
    if (val) {
      resolve(true);
    } else {
      reject(false);
    }
  });
}

// Call the promise
myPromiseFn(true) // first call
.then(function (val) { // true
  return myPromiseFn(val); // second call
})
.then(function (val) { // true
  val = false;
  return myPromiseFn(val); // third call
});
.catch(function (val) { // false
  // will catch the rejection
});

Promises gave use a bit of structure around asynchronous code.

If I'm being totally honest, it took me a few days to understand how to create a promise and how to properly use them.

They went against everything I had learned about JavaScript. How can that single catch handler get the value of the third promise?

At the time I was also learning AngularJS and had some experience with jQuery's implementation. Today's Promises are much simpler than the pre-specification Promises based on q and bluebird.

You're probably wondering when I'm going to tell you why you should be using Async/Await.

You've reached that point of the article.

Async/Await does much behind the scene that you shouldn't worry about how it's implemented. But, you probably care a little bit so I'll indulge your curiosity.

When JavaScript adopts new features it must remain backward compatible. Code written 20 years ago should be able to execute on today's modern browsers.

You know how I mentioned Promises up above? Async Functions are the product of multiple next-gen features like generators, yield, and Promises.

Let's take the myPromiseFn function example above and re-write it using Async/Await

// Create the async function
async function myAsyncFn(val) {
  if (val) {
    return await true;
  } else {
    throw false;
  }
}

// Call the async function
myAsyncFn(true) // first call
.then(function (val) { // true
  return myAsyncFn(val); // second call
})
.then(function (val) { // true
  val = false;
  return myAsyncFn(val); // third call
});
.catch(function (val) { // false
  // will catch the rejection
  console.error('Error:', val);
});

That's cool, right? But I think I can do better.

// Create the async function
async function myAsyncFn(val) {
  if (val) {
    return await true;
  } else {
    throw false;
  }
}

(async function () {
  try {
    let val = await myAsyncFn(true);
    val = await myAsyncFn(false); // rejected here
  } catch (exc) {
    console.error('Error:', exc);
  }
})();

This example highlights an important part Async Functions. Once you start, you can't stop! An Async Function demands that you call the Async Function inside another Async Function... Luckily you have the escape hatch of a IIFE if you are ever in need!

Get Async/Await In Your Code

I write a lot of TypeScript so that's what I'm going to walk you through.

If you are looking for a guide on using Async/Await in Babel, this article is not for you. But please share whatever you find on the topic in the comments. I did some searching but found a lot of old blog posts and some referencing older versions of Babel. I don't want to spread misinformation.

First you'll need to know you are going to be dependent on Promises in an ES5 environment. We'll need to use a Promise polyfill. I recommend grabbing the es6-promise.auto.js version since it automatically applies the polyfill.

Next thing to do is configure TypeScript to provide type definitions for Promises while downleveling to ES5. Our tsconfig.json file will look something like this:

{
    "compilerOptions": {
        "lib": ["dom", "es2015.promise", "es5"]
    }
}
  • dom provides type definitions for the browser's DOM API.
  • es2015.promise is the type definition we need to use Async/Await properly.
  • es5 is the remaining type definitions we are targeting.

Now you're all set to write Async Functions in TypeScript.

Here's some example code to try out:

<!DOCTYPE html>
<html>
  <head>
    <title>Async/Await</title>
  </head>
  <body>

  <script src="es6-promise.auto.js"></script>
  <script src="async-logger.js"></script>
  </body>
</html>
function delay(ms = 500) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms);
  });
}

async function log(message: string) {
  await delay();
  console.log(message);
}

(async function() {
  await log('first');
  await log('second');
  await log('third');
})();

Async/Await In Action

async functions in action

Go head and fork this pen and get started with Async/Await today!

Was this article helpful? Let me know in the comments.