async/await functions simplify promises to use synchronously. Most async functions can be written using Promises. However, using the try/catch construct, async/await makes it relatively easy to handle both synchronous and asynchronous errors:

In this promise example above, the try/catch will not handle the error if JSON.parse fails because it’s happening inside a promise. We can simplify it with async/await :

With async/await, the catch block will handle parsing errors which is much more efficient, simple and less complicated.

It’s easier to handle conditionals usingasync/await compared to using Promises. Often times, we want to fetch some data and then decide whether it should return that fetched data or get more data based on some value in the initially fetched data. For instance:

This could get complicated and confusing as you go on with values that require other values, however, async/await makes it really simple to handle:

Consider a situation where we have a sequence of asynchronous tasks to be done one after another. For example, loading scripts or returning Promises from an API etc. It will result in a promise chain and we’ll have to split the functions into many parts to handle it. Consider this example:

Here the flow is:

  1. The initial content(url) resolves
  2. Then the .then handler is called
  3. The value that it returns is passed to the next .then handler
  4. If an error occurs, the catch handler handles it

As the result is passed along the chain of handlers, we can see even more functions being created to handle it.

However, that entire chain can be rewritten with a single async function:

The way Promises report errors are quite misleading and complicated as compared to async/await. Consider a function that calls multiple Promises in a chain:

This suggests that the error occurs from fetch() whereas, in essence, it doesn’t. As can be seen from the code, the error clearly is as a result of the foo() method but there was no mention of it in the stack.
However, if we are to rewrite the code in async/await syntax:

Now, this points exactly to the foo() method and better still, it points to the exact location of the error in the codebase.

This is an extension of the error reporting function above however with more attention to performance and memory efficiency. Imagine a scenario where a function do is called when a call to an asynchronous function boo resolves:

When foo is called, the following happens synchronously:

  • boo is called and returns a promise that will resolve at some point in the future.
  • The .then callback (which is effectively calling do()) is added to the callback chain.

After that, we’re done executing the code in the body of the function foo. Note: foo is never suspended, and the context is gone by the time the asynchronous call to boo resolves. Imagine what happens if boo (or do) asynchronously throws an exception. The stack trace should include foo, since that’s where boo (or do) was called from, right? How is that possible now that we have no reference to foo anymore? That’s exactly the same case we had on the third step above.

To make it work, the JavaScript engine needs to do something in addition to the above steps,
it also captures and stores the stack trace within foo while it still has the chance. Capturing the stack trace takes time (i.e. degrades performance); storing these stack traces requires memory.

Here’s the same program, written using async/await :

With await, there’s no need to store the current stack trace. During the execution of boo, foo is suspended, so its context is still available. If boo throws an exception, the stack trace can be reconstructed on-demand by traversing these pointers. If doe throws an exception, the stack trace can be constructed just like it would be for asynchronous function, because we’re still within foo when that happens. Either way, stack trace capturing is no longer necessary — instead, the stack trace is only constructed when needed. Storing the pointers requires less memory than storing entire stack traces

The async/await syntax is generally very clean and concise. Considering our previous examples, you can look at how much code we didn’t have to write. it’s clear we saved a decent amount of code (thereby saving us time and effort). We didn’t have to:

  • Write .then
  • Create an anonymous function to handle responses
  • Name variables that we don’t need to use
  • We also avoided nesting our code.

These small advantages add up quickly, to enhance both the code structure and the javascript engine functions.

😀 Full-Stack Web Developer 🤓 JavaScript 😄 React 😁 React Hooks 🙂 Node.js