Introduction to JavaScript Async
Functions- Promises simplified

Created: March 27th, 17'

JavaScript Promises
provides us with an elegant way to write asynchronous code that avoids
piling on callbacks after callbacks. While the syntax for Promises is
fairly succinct, at the end of the day, it still looks like asynchronous
code, especially as you begin to chain promises together with a series
of then():

Note that I'm using
JavaScript Arrow Functions inside then(). While the
Promises Pattern is much better than nested callbacks, there is still a
sense of "unnaturalness" and convolution about it with the long chain.
And where there is a need for something better, leave it up to the
JavaScript Gods (or the ECMAScript Body) to provide it, in this case,
Async functions. Part of ECMAscript 6, Async Functions works alongside
Promises to make the later fit in better with the rest of the language,
by upending the later's syntax so it appears synchronous, one line
followed by the next. The result is asynchronous code that's easier to
write, follow, and debug, as it now falls more inline with how most
JavaScript code is written, in a linear, procedural manner. Async
functions are
already supported in the newer versions of Chrome (55) and FF (52),
and IE Edge 15 should follow suit too.

To give you a taste of JavaScript async
functions, here's how the above code looks like using an async function
instead:

So much cleaner, and well, normal looking! Lets see in detail now how to
define and utilize async functions, soon to be your Promises' new best
friend.

The Anatomy of an Async Function

Async functions are defined by placing the async keyword in front of a
function, such as:

async fetchdata(url){
// Do something
// Always returns a promise
}

This does two things:

It causes the function to always return a promise whether or
not you explicitly return something, so you can call then()
on it for example. More on this later.

It allows you to use the await keyword inside it to
wait on a promise until it is resolved before continuing
on to the next line inside the async function.

The await keyword

This brings us to the second part of an async function, which is the
await keyword. This is where most of the magic of async
functions happen. Using await, we can hit the pause button and wait for
a function that returns a promise inside an async function to resolve before moving on to
the next line inside the async function. The result is asynchronous code expressed
in a linear, sequential manner that's much easier to follow:

Here we assume function fetchtext() asynchronously fetches
some text and returns a promise that resolves to its contents. By placing
the await keyword in front of fetchtext() when
invoking it, everything else that follows the invocation pauses until
fetchtext() has resolved. One can think of
await as having the same effect as calling then()
on an asynchronous function and placing everything else that follows inside
it. When we use await multiple times, each awaited function
waits for the resolution of the previous before executing.

Recall that a function marked as async always returns a promise. If we
explicitly return a value at the end of our async function (as in line 5
above), the promise will be resolved with that value (otherwise, it resolves
with undefined). The fact that async functions always returns a promise
makes them non blocking, even though asynchronous operations inside them are
run sequentially. That is why we're able to call then() after an async
function call in line 8 above, with the explicitly returned value made available via
the parameter.

"Async
functions always returns a promise. If we explicitly return a value at
the end of our async function, the promise will be resolved with that value;
otherwise, it resolves with undefined."

Just to help you better grasp the underpinnings of the async function
pattern, lets see how the above code would look like using Promises only:

Which version do you - and more importantly - other people looking at
your code - prefer? Most of your Promises based code will inescapably
consist of a bunch of then()s and multiple return statements that using
async functions you can minimize to make the code much more legible.

Handling errors inside an Async function

So far we haven't talked about dealing with errors inside an Async
function. For example, given the following function, what happens when
the awaited function fetchtext() doesn't resolve, but instead rejects
its promise?

When an awaited function rejects its promise or throws an error, the error
by default is swallowed silently, and execution of the reminder of
the async function aborted. This means the 2nd and 3rd lines in the
above function would never get run. fetchdata() when run
will return a promise that's been rejected with the rejected value (if
defined). While we could use the catch() method of
JavaScript Promises to handle the rejection (as seen above), a more
elegant way is simply to use a try/catch block inside the
async function itself to handle rejections and errors:

Using try/catch inside an async function, we can forgo having
to always call catch(), but instead handle the error
directly inside where it happened, like with other synchronous code.
The value of err would simply be the value passed into reject()
inside function fetchtext(). With a try/catch block in place to
gracefully deal with rejections inside the async function, running
fetchdata() will return a promise that's fulfilled (resolved to
undefined or the return value inside the catch()
block), even though the awaited function inside returns a rejected
promise. Contrast that with when there is no try/catch block-
fetchdata() in that case returns a rejected promise itself as
well.

In general it's recommended that you take advantage of try/catch whenever
defining async functions to deal with errors explicitly and all in one
place, right inside the async function.

Await in parallel versus in sequence

When we have a series of await functions being called, they are executed
in order, one after the resolution of the previous:

Unless each await function requires some data from the previous, this
isn't the most optimal arrangement, as it means the amount of time it
takes for fetchdata() to complete is the sum of all of the awaited
functions' execution times. In situations like these, a better approach
is to run the functions in parallel, which can be done with the help of
Promise.all:

Promise.all accepts an array of promises and returns a
"super" promise when all of them have resolved, run in parallel. The
super promise resolves to an array containing the resolved value of each
of the "child" promises. By awaiting on Promise.all, we
retrieve this array once it's available.

Immediately Invoked Async Functions

Last but not least, async functions like regular (usually anonymous) functions can also be
invoked at the same time they're defined, via the IIFE (Immediately
Invoked Function Expression) pattern:

(async function(){
await fetchtext('snippet.txt')
})();

Using arrow functions:

(async () => {
await fetchtext('snippet.txt')
})();

We can then call then() immediately following it to process
any resolved value:

Conclusion

With more and more tasks we perform in JavaScript being asynchronous in
nature, any addition to the language that helps us more succinctly and
intuitively define those operations is greatly welcomed. As you can see, async functions does not seek to replace or supplant JavaScript Promises
- being it is based on Promises itself - but provide a way to express
Promises in a much more familiar form that is synchronous. And
familiarity is usually a good thing.