Move Over Promises – Async/Await Is Here

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 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(<span class="hljs-number">1</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"><span class="hljs-number">2</span></span>) </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"><span class="hljs-number">3</span>, function (<span class="hljs-number">4</span></span>) </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"><span class="hljs-number">5</span>, function (<span class="hljs-number">6</span></span>) </span>{
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Where am I?'</span>);
    });
  });
});

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).

<span class="hljs-comment">// Create the promise</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myPromiseFn</span> (<span class="hljs-params">val</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">resolve, reject</span>) </span>{
    <span class="hljs-keyword">if</span> (val) {
      resolve(<span class="hljs-literal">true</span>);
    } <span class="hljs-keyword">else</span> {
      reject(<span class="hljs-literal">false</span>);
    }
  });
}

<span class="hljs-comment">// Call the promise</span>
myPromiseFn(<span class="hljs-literal">true</span>) <span class="hljs-comment">// first call</span>
.then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{ <span class="hljs-comment">// true</span>
  <span class="hljs-keyword">return</span> myPromiseFn(val); <span class="hljs-comment">// second call</span>
})
.then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{ <span class="hljs-comment">// true</span>
  val = <span class="hljs-literal">false</span>;
  <span class="hljs-keyword">return</span> myPromiseFn(val); <span class="hljs-comment">// third call</span>
});
.catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{ <span class="hljs-comment">// false</span>
  <span class="hljs-comment">// will catch the rejection</span>
});

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 catchhandler 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 generatorsyield, and Promises.

Let’s take the <strong>myPromiseFn</strong> function example above and re-write it using Async/Await

<span class="hljs-comment">// Create the async function</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myAsyncFn</span>(<span class="hljs-params">val</span>) </span>{
  <span class="hljs-keyword">if</span> (val) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-literal">true</span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">throw</span> <span class="hljs-literal">false</span>;
  }
}

<span class="hljs-comment">// Call the async function</span>
myAsyncFn(<span class="hljs-literal">true</span>) <span class="hljs-comment">// first call</span>
.then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{ <span class="hljs-comment">// true</span>
  <span class="hljs-keyword">return</span> myAsyncFn(val); <span class="hljs-comment">// second call</span>
})
.then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{ <span class="hljs-comment">// true</span>
  val = <span class="hljs-literal">false</span>;
  <span class="hljs-keyword">return</span> myAsyncFn(val); <span class="hljs-comment">// third call</span>
});
.catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{ <span class="hljs-comment">// false</span>
  <span class="hljs-comment">// will catch the rejection</span>
  <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error:'</span>, val);
});

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

<span class="hljs-comment">// Create the async function</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myAsyncFn</span>(<span class="hljs-params">val</span>) </span>{
  <span class="hljs-keyword">if</span> (val) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-literal">true</span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">throw</span> <span class="hljs-literal">false</span>;
  }
}

(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">let</span> val = <span class="hljs-keyword">await</span> myAsyncFn(<span class="hljs-literal">true</span>);
    val = <span class="hljs-keyword">await</span> myAsyncFn(<span class="hljs-literal">false</span>); <span class="hljs-comment">// rejected here</span>
  } <span class="hljs-keyword">catch</span> (exc) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error:'</span>, 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 <strong>tsconfig.json</strong> file will look something like this:

{
    <span class="hljs-string">"compilerOptions"</span>: {
        <span class="hljs-string">"lib"</span>: [<span class="hljs-string">"dom"</span>, <span class="hljs-string">"es2015.promise"</span>, <span class="hljs-string">"es5"</span>]
    }
}
  • <strong>dom</strong> provides type definitions for the browser’s DOM API.
  • <strong>es2015.promise</strong> is the type definition we need to use Async/Await properly.
  • <strong>es5</strong> 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:

<span class="hljs-meta"><!DOCTYPE html></span>
<span class="hljs-tag"><<span class="hljs-name">html</span>></span>
  <span class="hljs-tag"><<span class="hljs-name">head</span>></span>
    <span class="hljs-tag"><<span class="hljs-name">title</span>></span>Async/Await<span class="hljs-tag"></<span class="hljs-name">title</span>></span>
  <span class="hljs-tag"></<span class="hljs-name">head</span>></span>
  <span class="hljs-tag"><<span class="hljs-name">body</span>></span>

  <span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"es6-promise.auto.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
  <span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"async-logger.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
  <span class="hljs-tag"></<span class="hljs-name">body</span>></span>
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delay</span>(<span class="hljs-params">ms = <span class="hljs-number">500</span></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> {
    setTimeout(resolve, ms);
  });
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">log</span>(<span class="hljs-params">message: string</span>) </span>{
  <span class="hljs-keyword">await</span> delay();
  <span class="hljs-built_in">console</span>.log(message);
}

(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>() </span>{
  <span class="hljs-keyword">await</span> log(<span class="hljs-string">'first'</span>);
  <span class="hljs-keyword">await</span> log(<span class="hljs-string">'second'</span>);
  <span class="hljs-keyword">await</span> log(<span class="hljs-string">'third'</span>);
})();

Async/Await In Action

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

CSG Pro

CSG Pro

Our data analytics consultants solve problems and ignite victories. We help you understand your data so you can make smarter business decisions. We build custom software applications that strengthen your process and your team.
SHARE THIS
Share on twitter
Share on facebook
Share on linkedin
Share on email
RELATED POSTS

Subscribe

Subscribe to CSG Pro. We’ll supply your inbox with the latest blog posts, training videos, and upcoming events.

Ready to wrangle your data?