Async/await

There’s a special syntax to work with promises in a more comfortable fashion, called “async/await”. It’s surprisingly easy to understand and use.

Async functions

Let’s start with the async keyword. It can be placed before a function, like this:

The word “async” before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically.

For instance, this function returns a resolved promise with the result of 1 ; let’s test it:

…We could explicitly return a promise, which would be the same:

So, async ensures that the function returns a promise, and wraps non-promises in it. Simple enough, right? But not only that. There’s another keyword, await , that works only inside async functions, and it’s pretty cool.

The syntax:

The keyword await makes JavaScript wait until that promise settles and returns its result.

Here’s an example with a promise that resolves in 1 second:

The function execution “pauses” at the line (*) and resumes when the promise settles, with result becoming its result. So the code above shows “done!” in one second.

Let’s emphasize: await literally suspends the function execution until the promise settles, and then resumes it with the promise result. That doesn’t cost any CPU resources, because the JavaScript engine can do other jobs in the meantime: execute other scripts, handle events, etc.

It’s just a more elegant syntax of getting the promise result than promise.then . And, it’s easier to read and write.

If we try to use await in a non-async function, there would be a syntax error:

We may get this error if we forget to put async before a function. As stated earlier, await only works inside an async function.

Let’s take the showAvatar() example from the chapter Promises chaining and rewrite it using async/await :

  • We’ll need to replace .then calls with await .
  • Also we should make the function async for them to work.

Pretty clean and easy to read, right? Much better than before.

In modern browsers, await on top level works just fine, when we’re inside a module. We’ll cover modules in article Modules, introduction .

For instance:

If we’re not using modules, or older browsers must be supported, there’s a universal recipe: wrapping into an anonymous async function.

Like promise.then , await allows us to use thenable objects (those with a callable then method). The idea is that a third-party object may not be a promise, but promise-compatible: if it supports .then , that’s enough to use it with await .

Here’s a demo Thenable class; the await below accepts its instances:

If await gets a non-promise object with .then , it calls that method providing the built-in functions resolve and reject as arguments (just as it does for a regular Promise executor). Then await waits until one of them is called (in the example above it happens in the line (*) ) and then proceeds with the result.

To declare an async class method, just prepend it with async :

The meaning is the same: it ensures that the returned value is a promise and enables await .

Error handling

If a promise resolves normally, then await promise returns the result. But in the case of a rejection, it throws the error, just as if there were a throw statement at that line.

…is the same as this:

In real situations, the promise may take some time before it rejects. In that case there will be a delay before await throws an error.

We can catch that error using try..catch , the same way as a regular throw :

In the case of an error, the control jumps to the catch block. We can also wrap multiple lines:

If we don’t have try..catch , then the promise generated by the call of the async function f() becomes rejected. We can append .catch to handle it:

If we forget to add .catch there, then we get an unhandled promise error (viewable in the console). We can catch such errors using a global unhandledrejection event handler as described in the chapter Error handling with promises .

When we use async/await , we rarely need .then , because await handles the waiting for us. And we can use a regular try..catch instead of .catch . That’s usually (but not always) more convenient.

But at the top level of the code, when we’re outside any async function, we’re syntactically unable to use await , so it’s a normal practice to add .then/catch to handle the final result or falling-through error, like in the line (*) of the example above.

When we need to wait for multiple promises, we can wrap them in Promise.all and then await :

In the case of an error, it propagates as usual, from the failed promise to Promise.all , and then becomes an exception that we can catch using try..catch around the call.

The async keyword before a function has two effects:

  • Makes it always return a promise.
  • Allows await to be used in it.

The await keyword before a promise makes JavaScript wait until that promise settles, and then:

  • If it’s an error, an exception is generated — same as if throw error were called at that very place.
  • Otherwise, it returns the result.

Together they provide a great framework to write asynchronous code that is easy to both read and write.

With async/await we rarely need to write promise.then/catch , but we still shouldn’t forget that they are based on promises, because sometimes (e.g. in the outermost scope) we have to use these methods. Also Promise.all is nice when we are waiting for many tasks simultaneously.

Rewrite using async/await

Rewrite this example code from the chapter Promises chaining using async/await instead of .then/catch :

The notes are below the code:

The function loadJson becomes async .

All .then inside are replaced with await .

We can return response.json() instead of awaiting for it, like this:

Then the outer code would have to await for that promise to resolve. In our case it doesn’t matter.

The error thrown from loadJson is handled by .catch . We can’t use await loadJson(…) there, because we’re not in an async function.

Rewrite "rethrow" with async/await

Below you can find the “rethrow” example. Rewrite it using async/await instead of .then/catch .

And get rid of the recursion in favour of a loop in demoGithubUser : with async/await that becomes easy to do.

There are no tricks here. Just replace .catch with try..catch inside demoGithubUser and add async/await where needed:

Call async from non-async

We have a “regular” function called f . How can you call the async function wait() and use its result inside of f ?

P.S. The task is technically very simple, but the question is quite common for developers new to async/await.

That’s the case when knowing how it works inside is helpful.

Just treat async call as promise and attach .then to it:

Lesson navigation

  • © 2007—2024  Ilya Kantor
  • about the project
  • terms of usage
  • privacy policy

James Hibbard

A Beginner’s Guide to JavaScript async/await, with Examples

Share this article

A Beginner's Guide to JavaScript async/await, with Examples

How to Create a JavaScript Async Function

Javascript await/async uses promises under the hood, error handling in async functions, running asynchronous commands in parallel, asynchronous awaits in synchronous loops, top-level await, write asynchronous code with confidence, faqs about javascript async/await.

The async and await keywords in JavaScript provide a modern syntax to help us handle asynchronous operations. In this tutorial, we’ll take an in-depth look at how to use async/await to master flow control in our JavaScript programs.

The async keyword

The await keyword, different ways of declaring async functions, switching from promises to async/await.

  • Making use of catch() on the function call

In JavaScript, some operations are asynchronous . This means that the result or value they produce isn’t immediately available.

Consider the following code:

The JavaScript interpreter won’t wait for the asynchronous fetchDataFromApi function to complete before moving on to the next statement. Consequently, it logs Finished fetching data before logging the actual data returned from the API.

In many cases, this isn’t the desired behavior. Luckily, we can use the async and await keywords to make our program wait for the asynchronous operation to complete before moving on.

This functionality was introduced to JavaScript in ES2017 and is supported in all modern browsers .

For a comprehensive introduction on JavaScript and asynchronous programming, check out our free book: Learn to Code with JavaScript . 

Let’s take a closer look at the data fetching logic in our fetchDataFromApi function. Data fetching in JavaScript is a prime example of an asynchronous operation.

Using the Fetch API , we could do something like this:

Here, we’re fetching a programming joke from the JokeAPI . The API’s response is in JSON format, so we extract that response once the request completes (using the json() method), then log the joke to the console.

Please note that the JokeAPI is a third-party API, so we can’t guarantee the quality of jokes that will be returned!

If we run this code in your browser, or in Node (version 17.5+ using the --experimental-fetch flag), we’ll see that things are still logged to the console in the wrong order.

Let’s change that.

The first thing we need to do is label the containing function as being asynchronous. We can do this by using the async keyword, which we place in front of the function keyword:

Asynchronous functions always return a promise (more on that later), so it would already be possible to get the correct execution order by chaining a then() onto the function call:

If we run the code now, we see something like this:

But we don’t want to do that! JavaScript’s promise syntax can get a little hairy, and this is where async/await shines: it enables us to write asynchronous code with a syntax which looks more like synchronous code and which is more readable.

The next thing to do is to put the await keyword in front of any asynchronous operations within our function. This will force the JavaScript interpreter to “pause” execution and wait for the result. We can assign the results of these operations to variables:

We also need to wait for the result of calling the fetchDataFromApi function:

Unfortunately, if we try to run the code now, we’ll encounter an error:

This is because we can’t use await outside of an async function in a non-module script. We’ll get into this in more detail later , but for now the easiest way to solve the problem is by wrapping the calling code in a function of its own, which we’ll also mark as async :

If we run the code now, everything should output in the correct order:

The fact that we need this extra boilerplate is unfortunate, but in my opinion the code is still easier to read than the promise-based version.

The previous example uses two named function declarations (the function keyword followed by the function name), but we aren’t limited to these. We can also mark function expressions, arrow functions and anonymous functions as being async .

If you’d like a refresher on the difference between function declarations and function expressions, check out our guide on when to use which .

Async function expression

A function expression is when we create a function and assign it to a variable. The function is anonymous, which means it doesn’t have a name. For example:

This would work in exactly the same way as our previous code.

Async arrow function

Arrow functions were introduced to the language in ES6. They’re a compact alternative to function expressions and are always anonymous. Their basic syntax is as follows:

To mark an arrow function as asynchronous, insert the async keyword before the opening parenthesis.

For example, an alternative to creating an additional init function in the code above would be to wrap the existing code in an IIFE , which we mark as async :

There’s not a big difference between using function expressions or function declarations: mostly it’s just a matter of preference. But there are a couple of things to be aware of, such as hoisting, or the fact that an arrow function doesn’t bind its own this value. You can check the links above for more details.

As you might have already guessed, async/await is, to a large extent, syntactic sugar for promises. Let’s look at this in a little more detail, as a better understanding of what’s happening under the hood will go a long way to understanding how async/await works.

If you’re not sure what promises are, or if you’d like a quick refresher, check out our promises guide .

The first thing to be aware of is that an async function will always return a promise, even if we don’t explicitly tell it to do so. For example:

This logs the following:

A promise can be in one of three states: pending , fulfilled , or rejected . A promise starts life in a pending state. If the action relating to the promise is successful, the promise is said to be fulfilled . If the action is unsuccessful, the promise is said to be rejected . Once a promise is either fulfilled or rejected, but not pending, it’s also considered settled .

When we use the await keyword inside of an async function to “pause” function execution, what’s really happening is that we’re waiting for a promise (either explicit or implicit) to settle into a resolved or a rejected state.

Building on our above example, we can do the following:

Because the echo function returns a promise and the await keyword inside the getValue function waits for this promise to fulfill before continuing with the program, we’re able to log the desired value to the console.

Promises are a big improvement to flow control in JavaScript and are used by several of the newer browser APIs — such as the Battery status API , the Clipboard API , the Fetch API , the MediaDevices API , and so on.

Node has also added a promisify function to its built-in util module that converts code that uses callback functions to return promises. And as of v10, functions in Node’s fs module can return promises directly.

So why does any of this matter to us?

Well, the good news is that any function that returns a promise can be used with async/await . I’m not saying that we should async/await all the things (this syntax does have its downsides, as we’ll see when we get on to error handling), but we should be aware that this is possible.

We’ve already seen how to alter our promise-based fetch call at the top of the article to work with async/await , so let’s have a look at another example. Here’s a small utility function to get the contents of a file using Node’s promise-based API and its readFile method.

Using Promise.then() :

With async/await that becomes:

Note: this is making use of a feature called top-level await , which is only available within ES modules. To run this code, save the file as index.mjs and use a version of Node >= 14.8.

Although these are simple examples, I find the async/await syntax easier to follow. This becomes especially true when dealing with multiple then() statements and with error handling thrown in to the mix. I wouldn’t go as far as converting existing promise-based code to use async/await , but if that’s something you’re interested in, VS Code can do it for you .

There are a couple of ways to handle errors when dealing with async functions. Probably the most common is to use a try...catch block, which we can wrap around asynchronous operations and catch any errors which occur.

In the following example, note how I’ve altered the URL to something that doesn’t exist:

This will result in the following message being logged to the console:

This works because fetch returns a promise. When the fetch operation fails, the promise’s reject method is called and the await keyword converts that unhanded rejection to a catchable error.

However, there are a couple of problems with this method. The main criticism is that it’s verbose and rather ugly. Imagine we were building a CRUD app and we had a separate function for each of the CRUD methods (create, read, update, destroy). If each of these methods performed an asynchronous API call, we’d have to wrap each call in its own try...catch block. That’s quite a bit of extra code.

The other problem is that, if we haven’t used the await keyword, this results in an unhandled promise rejection:

The code above logs the following:

Unlike await , the return keyword doesn’t convert promise rejections to catchable errors.

Making Use of catch() on the function call

Every function that returns a promise can make use of a promise’s catch method to handle any promise rejections which might occur.

With this simple addition, the code in the above example will handle the error gracefully:

And now this outputs the following:

As to which strategy to use, I agree with the advice of Valeri Karpov . Use try/catch to recover from expected errors inside async functions, but handle unexpected errors by adding a catch() to the calling function.

When we use the await keyword to wait for an asynchronous operation to complete, the JavaScript interpreter will accordingly pause execution. While this is handy, this might not always be what we want. Consider the following code:

Here we are making two API calls to get the number of GitHub stars for React and Vue respectively. While this works just fine, there’s no reason for us to wait for the first resolved promise before we make the second fetch request. This would be quite a bottleneck if we were making many requests.

To remedy this, we can reach for Promise.all , which takes an array of promises and waits for all promises to be resolved or for any one of them to be rejected:

Much better!

At some point, we’ll try calling an asynchronous function inside a synchronous loop. For example:

This won’t work as expected, as forEach will only invoke the function without waiting for it to complete and the following will be logged to the console:

The same thing applies to many of the other array methods, such as map , filter and reduce .

Luckily, ES2018 introduced asynchronous iterators, which are just like regular iterators except their next() method returns a promise. This means we can use await within them. Let’s rewrite the above code using one of these new iterators — for…of :

Now the process function outputs everything in the correct order:

As with our previous example of awaiting asynchronous fetch requests, this will also come at a performance cost. Each await inside the for loop will block the event loop, and the code should usually be refactored to create all the promises at once, then get access to the results using Promise.all() .

There is even an ESLint rule which complains if it detects this behavior.

Finally, let’s look at something called top-level await. This is was introduced to the language in ES2022 and has been available in Node as of v14.8.

We’ve already been bitten by the problem that this aims to solve when we ran our code at the start of the article. Remember this error?

This happens when we try to use await outside of an async function. For example, at the top level of our code:

Top-level await solves this problem, making the above code valid, but only within an ES module . If we’re working in the browser, we could add this code to a file called index.js , then load it into our page like so:

And things will work as expected — with no need for a wrapper function or the ugly IIFE.

Things get more interesting in Node. To declare a file as an ES module, we should do one of two things. One option is to save with an .mjs extension and run it like so:

The other option is to set "type": "module" in the package.json file:

Top-level await also plays nicely with dynamic imports — a function-like expression that allows us to load an ES module asynchronously. This returns a promise, and that promise resolves into a module object, meaning we can do something like this:

The dynamic imports option also lends itself well to lazy loading in combination with frameworks such as React and Vue. This enables us to reduce our initial bundle size and time to interactive metric.

In this article, we’ve looked at how you can manage the control flow of your JavaScript program using async/await . We’ve discussed the syntax, how async/await works under the hood, error handling, and a few gotchas. If you’ve made it this far, you’re now a pro. 🙂

Writing asynchronous code can be hard, especially for beginners, but now that you have a solid understanding of the techniques, you should be able to employ them to great effect.

Happy coding!

If you have any questions or comments, let me know on Twitter .

What is the main purpose of using async/await in JavaScript?

The main purpose of using async/await in JavaScript is to simplify the behavior of using promises synchronously and to perform some behavior on a group of Promises. It essentially allows you to work with Promises in a more comfortable synchronous manner. Async/await makes it easier to read (and therefore understand) asynchronous code. It makes it look like it’s synchronous, but it’s asynchronous and non-blocking behind the scenes.

Can I use async/await with any function in JavaScript?

No, you can’t use async/await with just any function. The function needs to be declared as async. This means that the function will return a Promise. If the function returns a value, the Promise will be resolved with the value, but if the function throws an exception, the Promise will be rejected with that value. You can then use await to wait for the Promise to be resolved or rejected.

What happens if I don’t handle rejections in async/await?

If a Promise is rejected and the rejection is not handled, it will result in an unhandled promise rejection. This is similar to an uncaught exception, and most JavaScript environments will report this as an error. It’s important to always handle Promise rejections when using async/await.

Can I use async/await in a loop?

Yes, you can use async/await in a loop. However, be aware that if you’re using await in a loop, each iteration will wait for the Promise to resolve before moving on to the next one. This means that if you’re not careful, your async functions could end up running in series instead of in parallel.

How can I handle errors in async/await?

You can handle errors in async/await using try/catch blocks. The try block contains the code that might throw an exception, and the catch block contains the code to handle the error. This is a similar concept to error handling in synchronous code.

Can I use Promise methods with async/await?

Yes, you can use Promise methods like .then(), .catch(), and .finally() with async/await. These methods can be useful for handling the results of async functions, especially when dealing with multiple Promises.

Can I use async/await in all browsers?

As of now, async/await is supported in most modern browsers, including Chrome, Firefox, Safari, and Edge. However, it’s not supported in Internet Explorer. If you need to support older browsers, you might need to use a transpiler like Babel to convert your async/await code into ES5 code.

Can I use async/await with callbacks?

No, async/await cannot be used with callbacks directly. Async/await is designed to work with Promises, not callbacks. However, you can convert a callback-based function into a Promise-based one, and then use async/await with that.

Can I use multiple awaits in a single async function?

Yes, you can use multiple await expressions in a single async function. Each await expression will pause the execution of the async function and wait for the Promise to resolve or reject, then resume the execution and return the resolved value.

Can I use async/await in Node.js?

Yes, you can use async/await in Node.js. As of Node.js 7.6.0, async/await is fully supported. This allows you to write asynchronous code in a more synchronous style, which can make your Node.js code easier to read and understand.

Network admin, freelance web developer and editor at SitePoint .

SitePoint Premium

Home » JavaScript Tutorial » JavaScript async/await

JavaScript async/await

Summary : in this tutorial, you will learn how to write asynchronous code  using JavaScript   async /  await keywords.

Note that to understand how the async / await works, you need to know how promises work.

Introduction to JavaScript async / await keywords

In the past, to handle asynchronous operations, you used the callback functions . However, nesting many callback functions can make your code more difficult to maintain, resulting in a notorious issue known as callback hell.

Suppose that you need to perform three asynchronous operations in the following sequence:

  • Select a user from the database.
  • Get the user’s services from an API.
  • Calculate the service cost based on the services from the server. 

The following functions illustrate the three tasks. Note that we use the setTimeout() function to simulate the asynchronous operation.

The following shows the nested callback functions:

To avoid this callback hell issue, ES6 introduced the promises that allow you to write asynchronous code in more manageable ways.

First, you need to return a Promise in each function:

Then, you chain the promises :

ES2017 introduced the async / await keywords that build on top of promises, allowing you to write asynchronous code that looks more like synchronous code and is more readable. Technically speaking, the async / await is syntactic sugar for promises.

If a function returns a Promise, you can place the await keyword in front of the function call, like this:

The await will wait for the Promise returned from the f() to settle. The await keyword can be used only inside the async functions.

The following defines an async function that calls the three asynchronous operations in sequence:

As you can see, the asynchronous code now looks like the synchronous code.

Let’s dive into the async / await keywords.

The async keyword

The async keyword allows you to define a function that handles asynchronous operations.

To define an async function, you place the async keyword in front of the function keyword as follows:

Asynchronous functions execute asynchronously via the event loop . It always returns a Promise . 

In this example, because the sayHi() function returns a Promise , you can consume it, like this:

You can also explicitly return a Promise from the sayHi() function as shown in the following code:

The effect is the same.

Besides the regular functions, you can use the async keyword in the function expressions:

arrow functions :

and methods of classes:

The await keyword

You use the await keyword to wait for a Promise to settle either in a resolved or rejected state. You can use the await keyword only inside an async function:

In this example, the await keyword instructs the JavaScript engine to wait for the sayHi() function to complete before displaying the message.

Note that if you use the await operator outside of an async function, you will get an error.

Error handling

If a promise resolves, the await promise returns the result. However, when the promise is rejected, the await promise will throw an error as if there were a throw statement.

The following code:

… is the same as this:

In a real scenario, it will take a while for the promise to throw an error.

You can catch the error by using the try...catch statement, the same way as a regular throw statement:

It’s possible to catch errors caused by one or more await promise ‘s:

In this tutorial, you have learned how to use the JavaScript async / await keyword to write asynchronous code looks like synchronous code.

How to Use Async/Await in JavaScript with Example JS Code

Nishant Kumar

In this tutorial, we are going to learn how to use Async/Await in JavaScript.

But before we get there, we should understand a few topics like:

  • Event loops

What are Event Loops in JavaScript?

Event loops are one of the most important aspects of JavaScript.

JavaScript is a single-threaded programming language which means that only one task can run at a time. It has a call stack and all the code is executed inside this call stack. Let’s understand with an example.

Pink-Cute-Chic-Vintage-90s-Virtual-Trivia-Quiz-Presentations--8-

In the above example, we can see that we are logging two values in the console.

When the First() finishes its execution, it will be popped out of the call stack and the event loop will go down to the next line. The next line will be stored in the call stack and will be flagged for execution.

Pink-Cute-Chic-Vintage-90s-Virtual-Trivia-Quiz-Presentations--9-

Our console will print the following result:

Pink-Cute-Chic-Vintage-90s-Virtual-Trivia-Quiz-Presentations--18-

To understand things better, let’s take a look at another example.

As usual, our code will move into the call stack and the event loop will loop through line by line.

We will get “First!” in the console and it will be moved out of the call stack.

Now, the event loop will move to the second line and push it into the call stack. It will encounter the setTimeout function, which is a Macro task, and it will be executed in the next event Loop.

And now, you might be wondering what a Macro task is. Well, it's a task that runs after all of the tasks in the Event Loop, or you might say, in the other Event Loop. The SetTimeout and SetInterval functions can be the example of a Macro task which runs after all of the other tasks are completed.

Pink-Cute-Chic-Vintage-90s-Virtual-Trivia-Quiz-Presentations--19-

Finally, the final line of code will be executed. We will get First in our console, then Final, and then Timed Out.

How Do Callback Functions Work in JavaScript?

Callback functions are those functions that have been passed to another function as an argument.

Let’s take a look at an example.

We have an array that contains the list of Star Wars movies and a function getMovies() to fetch the list.

Pink-Cute-Chic-Vintage-90s-Virtual-Trivia-Quiz-Presentations--20-

Let’s create another function called createMovie() . It will be used to add a new movie.

Pink-Cute-Chic-Vintage-90s-Virtual-Trivia-Quiz-Presentations--20--1

But the problem here is we are not getting the third movie on the console. That is because createMovie() takes longer than getMovies() . The createMovie() function took two seconds but getMovies() took only one second.

In other words, getMovies() runs before createMovies() and the list of Movies is already displayed.

To solve this, we can use Callbacks .

In createPost() , pass a function callback and call the function right after the new movie is pushed (instead of waiting two seconds).

Pink-Cute-Chic-Vintage-90s-Virtual-Trivia-Quiz-Presentations--21--2

Now we get the updated list of movies.

How Do Promises Work in JavaScript?

A promise is a value that may produce a value in the future. That value can either be resolved or unresolved (in some error cases, like a network failure). It works like a real-life promise.

It has three states: fulfilled, rejected, or pending.

  • Fulfilled: onFulfilled() will be called (for example, resolve() was called).
  • Rejected: onRejected() will be called (for example,   reject() was called).
  • Pending: not yet fulfilled or rejected.

Promise takes two parameters, resolve and reject. When something goes wrong, reject is called, or else resolve is called.

If we get an error, it will be something like ‘Error: Something went wrong!’, and if not, the promise will resolve.

Once the promise is resolved, it calls for the .then() keyword and getMovies() .

Finally, How Does Async/Await Work in JavaScript

Async means asynchronous. It allows a program to run a function without freezing the entire program. This is done using the Async/Await keyword.

Async/Await makes it easier to write promises. The keyword ‘async’ before a function makes the function return a promise, always. And the keyword await is used inside async functions, which makes the program wait until the Promise resolves.

The function execution “pauses” at the (*) line and resumes when the promise is fulfilled, with result becoming its result. So the code above shows “done!” in two seconds.

Let's take a look at a practice example.

In the above example, getMovies() at the (*) line is waiting for createMovies() to be executed in the async function.

In other words, createMovies() is async, so getMovies() will only run after createMovies() is done.

Now you know all the basics of Event Loops, Callbacks, Promises and Async/Await. These features were introduced in ECMAScript 2017, and they've made reading and writing JS code much easier and more effective.

That’s all folks! Happy learning and experimenting,

I build projects to learn how code works. And while I am not coding, I enjoy writing poetry and stories, playing the piano, and cooking delicious meals.

If you read this far, thank the author to show them you care. Say Thanks

Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. Get started

cod ; nn code. learn. thrive.

Code editor, async/await in javascript: the ultimate guide.

Async/Await in JavaScript: The Ultimate Guide

JavaScript's asynchronous model is based on the event loop, which allows for non-blocking I/O and improves performance.

While callbacks and promises have been the primary ways to handle asynchronous programming in JavaScript, async/await has become a popular alternative in recent years.

In this article, we'll explore what async/await is and how it works. We'll also look at some real-world examples and best practices for using async/await in your JavaScript projects.

Table of Contents

What is async/await, how async/await works, benefits of async/await, best practices for using async/await.

  • Real-World Examples

async/await is a syntactic sugar built on top of JavaScript's existing asynchronous programming model. It was introduced in ES2017 to simplify asynchronous programming and make it more readable and intuitive.

async/await allows you to write asynchronous code that looks and behaves like synchronous code. It uses keywords async and await to achieve this.

async is used to define a function that returns a promise, and await is used to wait for the promise to resolve or reject.

async/await is built on top of two key concepts: async functions and await operator.

Async Functions

async functions are functions that return a promise. They are defined using the async keyword before the function declaration.

Here's an example of an async function:

In the above example, the getData() function returns a promise that resolves to the data returned from the API.

The await keyword is used to wait for the fetch() and response.json() methods to complete before proceeding.

Await Operator

The await operator is used to wait for a promise to resolve or reject. It can only be used inside an async function.

Here's an example of using await:

In the above example, the await keyword is used to wait for the getData() function to return the data before assigning it to the data variable.

Error Handling

async/await also allows for better error handling than traditional callbacks or promises. You can use the try/catch statement to catch errors that occur in async functions.

Here's an example:

If an error occurs in the fetch() or response.json() methods, the catch block will catch the error and log it to the console.

async/await has several benefits over traditional callback or promise-based asynchronous programming:

Simplicity: async/await makes asynchronous programming simpler and more intuitive by allowing you to write asynchronous code that looks and behaves like synchronous code.

Error Handling: async/await allows for better error handling with the try/catch statement.

Readability: async/await makes code more readable by avoiding deep nesting of callbacks and promises.

Debugging: async/await makes debugging easier by allowing you to use traditional debugging techniques, like setting breakpoints and stepping through code.

While async/await can simplify asynchronous programming, it's important to follow best practices to avoid potential issues. Here are some best practices for using async/await:

Avoid Using Async/Await in Loops async/await should not be used in loops, as it can cause performance issues and make the code difficult to debug. Instead, you can use the Promise.all() method to run multiple asynchronous functions concurrently.

Use Promise.all() to Run Multiple Async Functions Concurrently Promise.all() allows you to run multiple asynchronous functions concurrently and wait for all of them to complete before proceeding.

This can improve performance and reduce the amount of time it takes for your code to execute.

In the above example, we use Promise.all() to run three asynchronous functions concurrently and wait for all of them to complete before returning the data.

Use try/catch for Error Handling async/await allows for better error handling with the try/catch statement. When using async/await, it's best practice to wrap your code in a try/catch block to handle errors that occur during execution.

Keep Functions Small and Focused It's a good practice to keep your async functions small and focused. Large async functions can be difficult to understand and debug, and can also negatively impact performance.

Real-World Examples Let's take a look at some real-world examples of using async/await.

Fetching Data from an API

In the above example, we use async/await to fetch data from an API and handle errors that occur during the process.

  • Uploading Files to a Server

In this example, we use async/await to upload a file to a server using the FormData API and handle errors that occur during the process.

async/await is a powerful feature in JavaScript that simplifies asynchronous programming and improves code readability. By using async/await with promises and the try/catch statement, you can write more efficient and error-resistant code.

1. What is the difference between async/await and promises?

async/await is a syntax feature that simplifies working with promises by allowing you to write asynchronous code that looks and behaves like synchronous code. Promises are a pattern for handling asynchronous code and are used in conjunction with async/await to provide a more readable and manageable codebase.

2. Can async/await be used with callbacks?

No, async/await cannot be used with callbacks. It is designed to work with promises, which provide a simpler and more intuitive way to work with asynchronous code.

3. What is the difference between async/await and generators?

async/await and generators are both used to handle asynchronous code, but they are fundamentally different. async/await is designed to work with promises and provides a simpler syntax for working with them. Generators, on the other hand, are used to create iterators and are more flexible in their usage.

4. Can async/await be used in all browsers?

async/await is supported in all modern browsers, but may not be supported in older browsers. To ensure that your code works across all browsers, it's a good practice to use a transpiler like Babel to convert your async/await code into ES5-compatible code.

5. Is it possible to use async/await without promises?

No, async/await is designed to work with promises and cannot be used without them. Promises provide a way to handle asynchronous code and are a fundamental part of working with async/await .

Hi, I'm Khang

Javascript: promise or async-await async without await, await without async.

The reason for this post is because I had some problems with wrapping my head around JavaScript asynchronous programming. I spent 4 hours scratching my head while fixing a bug in my game . Even though I had some basic experience with asynchronous programming when I worked with .Net, but many concepts in JS still got me confused (I’m not blaming the language tho, considering that I didn’t actually study JavaScript “the right way”).

It would have been faster if I had a basic grasp of JS asynchronous, that’s why I decided to summarize what I (may) have understood in this post.

JavaScript Basis

First, JavaScript is synchronous, blocking, single-threaded.

Which means if you’re executing a JS block of code on a page, then no other JavaScript on that page will be executed, only one operation can be processed at a time.

But what if we want to execute a function after another function has finished executing? That’s where we have callback.

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

Callback can be synchronous or asynchronous

Synchronous callback:

Example #1:

2 3 4 5 arr = ['a', 'b', 'c']; arr.forEach(function(item, index, array) { console.log(item, index) });
2 3 , 0 "b", 1 "c", 2

Here foreach function takes a callback and execute it synchronously, as foreach does not wait for promises.

Example #2:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 functionOne(value, callback) { var y = value + 5; callback(y); console.log('After callback'); } function functionTop() { var x = 5; console.log('x=' + x); functionOne(x, function(functionOneReturnedValue) { console.log('functionOne is executed, x=' + functionOneReturnedValue); // some useless job to cause waiting var a; for(var i = 0; i < 1000000000; i++){ a += i; } console.log('Done with callback'); }); console.log('After functionTop'); } functionTop();
2 3 4 5

Notice the order: ‘Done with callback’ => ‘After callback’ => ‘After functionTop’, showing that the callback call is synchronous, all functions execute in the order they are called.

Asynchronous callback

Example #3:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 x = false; function myFunction(callbackFn) { setTimeout( function() { console.log('inside setTimeout') callbackFn(); }, 0 ); } myFunction( function() { console.log('Start callback'); x = true; console.log('End callback'); }); console.log('Final x=' + x)
2 3 4 callback End callback

I used setTimeout to make myFunction run asynchronously, then pass a callback function into it. x still remains false , this is because any function given to the setTimeout function will be executed asynchronously, when the main thread is not busy.

Another example #4:

2 3 4 5 6 7 8 array = [1, 2, 3, 4, 5]; array.forEach((el, i) => { setTimeout(() => { console.log('setTimeout:' + el); }, 2000); console.log(el); });
2 3 4 5 6 7 8 9 10

As I mentioned above, foreach function takes a callback and executes it synchronously. setTimeout returns a value immediately, then the next line begins to execute, but the asynchronous callback ( setTimeout ) will be executed later.

Promise is a way to implement asynchronous programming in JavaScript. Promise was introduced in ES6 (ES2015).

MDN’s definition: The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

Differences between callback and promise

  • Callback is function, promise is object

Callback is a block of code which can be executed in response to events such as timer etc.

Promise is an object which stores information about whether the event has happened or not, if it has, what was the result.

  • Callback is passed as an argument, promise is returned

Callback is defined independently, is passed as an argument, and is stored in the function where it is called from.

Promise is created inside of asynchronous functions and then returned.

  • Callback can represent multiple events, promise represents one

Callback can be called multiple times by the function it is passed to.

Promise represents one event, a promise can only succeed or fail once.

promises.png

2 3 4 5 6 7 8 9 10 11 p = new Promise((resolve, reject) => { // In this example, I will use setTimeout(...) to simulate asynchronous code setTimeout( function() { resolve('Success!') }, 250) }) p.then((successMessage) => { // successMessage is whatever I passed in the resolve(...) function above console.log(successMessage) });

Running new Promise will immediately call the function passed in as an argument (here it means setTimeout is called immediately).

Promise constructor takes one argument: a callback with two parameters, resolve and reject .

You can use the promise result when it becomes settled with 3 methods: then , catch , finally .

These methods also return a newly generated promise object, which can optionally be used for chaining.

2 3 4 5 6 7 8 9 10 11 p = new Promise((resolve, reject) => { setTimeout( function() { reject('Error'); }, 250) }) p.then(function (msg) { console.log(msg); }).catch(function (err) { console.warn(err); });

async - await

ES2017 (ES8) introduced the concept of async functions and await keywords, a higher level abstraction over promises. They are just syntactic sugar on top of promises, making asynchronous code easier to write and to read.

First we have the async keyword:

  • When you put async in front of a function declaration, it turns the function into an async function
  • Async functions can contain zero or more await expressions
  • Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise

Then, the await keyword:

  • await only works inside async functions
  • Causes async function execution to pause until a promise is settled
  • If the Promise is rejected, the await expression throws the rejected value.
  • To await a function, that function must return a promise
2 3 4 5 6 7 8 9 10 function f() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve('done'), 1000) }); let result = await promise; // wait until the promise resolves console.log(result); } f();

The function execution will “pause” at the line where we used await , and resume when the promise settled.

Await a function without async

Since async is still promise-based, we can await a function that returns a promise, even when that function is not an async function:

2 3 4 5 6 7 8 9 10 11 12 13 f() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('done') }, 1000) }); } async function f1() { let result = await f(); console.log(result); } f1();

The below code has the same result:

2 3 4 5 6 7 8 9 10 11 12 13 function f() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('done') }, 1000) }); } async function f1() { let result = await f(); console.log(result); } f1();

Async function without await inside

We can declare a function as async without using any await . In this case, the execution is not paused and your code will be executed in a non-blocking manner (asynchronous - no waiting). It is the same as not declaring that same function with async .

2 3 4 5 6 7 8 9 10 11 12 13 14 function f() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('Promise resolved') resolve('done') }, 1000) }); } async function f1() { let result = f(); console.log('f1 finished'); } f1();
2

You can remove async keyword before f1 and still get the same result.

With await :

2 3 4 5 6 7 8 9 10 11 12 13 14 function f() { return new Promise((resolve, reject) => { setTimeout(() => { console.log('Promise resolved') resolve('done') }, 1000) }); } async function f1() { let result = await f(); console.log('f1 finished'); } f1();

Calling async without await

Be careful when calling an async function without await :

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 x = 0; function resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } async function f1() { x = await resolveAfter2Seconds(10); console.log('x inside f1:' + x); } f1(); x = 3; console.log('final x:' + x)

Since f1 is asynchronous, when it is executed, the line x = 3; executes immediately without waiting.

References:

MDN - Making asynchronous programming easier with async and await

MDN - async function

Introduction to ES6 Promises – The Four Functions You Need To Avoid Callback Hell

Stack Overflow - Await doesn&rsquo;t wait

Stack Overflow - Async function without await in Javascript

Async functions - making promises friendly

Stack Exchange - How does Javascript code become asynchronous when using callbacks?

Async JavaScript: From Callbacks, to Promises, to Async/Await

One of my favorite sites is BerkshireHathaway.com - it's simple, effective, and has been doing its job well since it launched in 1997. Even more remarkable, over the last 20 years, there's a good chance this site has never had a bug. Why? Because it's all static. It's been pretty much the same since it launched over 20 years ago. Turns out sites are pretty simple to build if you have all of your data up front. Unfortunately, most sites now days don't. To compensate for this, we've invented "patterns" for handling fetching external data for our apps. Like most things, these patterns each have tradeoffs that have changed over time. In this post, we'll break down the pros and cons of three of the most common patterns, Callbacks , Promises , and Async/Await and talk about their significance and progression from a historical context.

Let's start with the OG of these data fetching patterns, Callbacks.

I'm going to assume you know exactly 0 about callbacks. If I'm assuming wrong, just scroll down a bit.

When I was first learning to program, it helped me to think about functions as machines. These machines can do anything you want them to. They can even accept input and return a value. Each machine has a button on it that you can press when you want the machine to run, ().

Whether I press the button, you press the button, or someone else presses the button doesn't matter. Whenever the button is pressed, like it or not, the machine is going to run.

In the code above we assign the add function to three different variables, me , you , and someoneElse . It's important to note that the original add and each of the variables we created are pointing to the same spot in memory. They're literally the exact same thing under different names. So when we invoke me , you , or someoneElse , it's as if we're invoking add .

Now, what if we take our add machine and pass it to another machine? Remember, it doesn't matter who presses the () button, if it's pressed, it's going to run.

Your brain might have got a little weird on this one, nothing new is going on here though. Instead of "pressing the button" on add , we pass add as an argument to addFive , rename it addReference , and then we "press the button" or invoke it.

This highlights some important concepts of the JavaScript language. First, just as you can pass a string or a number as an argument to a function, so too can you pass a reference to a function as an argument. When you do this the function you're passing as an argument is called a callback function and the function you're passing the callback function to is called a higher order function .

Because vocabulary is important, here's the same code with the variables re-named to match the concepts they're demonstrating.

This pattern should look familiar, it's everywhere. If you've ever used any of the JavaScript Array methods, you've used a callback. If you've ever used lodash, you've used a callback. If you've ever used jQuery, you've used a callback.

In general, there are two popular use cases for callbacks. The first, and what we see in the .map and _.filter examples, is a nice abstraction over transforming one value into another. We say "Hey, here's an array and a function. Go ahead and get me a new value based on the function I gave you". The second, and what we see in the jQuery example, is delaying execution of a function until a particular time. "Hey, here's this function. Go ahead and invoke it whenever the element with an id of btn is clicked." It's this second use case that we're going to focus on, "delaying execution of a function until a particular time".

Right now we've only looked at examples that are synchronous. As we talked about at the beginning of this post, most of the apps we build don't have all the data they need up front. Instead, they need to fetch external data as the user interacts with the app. We've just seen how callbacks can be a great use case for this because, again, they allow you to "delay execution of a function until a particular time". It doesn't take much imagination to see how we can adapt that sentence to work with data fetching. Instead of delaying execution of a function until a particular time , we can delay execution of a function until we have the data we need . Here's probably the most popular example of this, jQuery's getJSON method.

We can't update the UI of our app until we have the user's data. So what do we do? We say, "Hey, here's an object. If the request succeeds, go ahead and call success passing it the user's data. If it doesn't, go ahead and call error passing it the error object. You don't need to worry about what each method does, just be sure to call them when you're supposed to". This is a perfect demonstration of using a callback for async requests.

At this point, we've learned about what callbacks are and how they can be beneficial both in synchronous and asynchronous code. What we haven't talked yet is the dark side of callbacks. Take a look at this code below. Can you tell what's happening?

If it helps, you can play around with the live version here .

Notice we've added a few more layers of callbacks. First, we're saying don't run the initial AJAX request until the element with an id of btn is clicked. Once the button is clicked, we make the first request. If that request succeeds, we make a second request. If that request succeeds, we invoke the updateUI method passing it the data we got from both requests. Regardless of if you understood the code at first glance or not, objectively it's much harder to read than the code before. This brings us to the topic of "Callback Hell".

As humans, we naturally think sequentially. When you have nested callbacks inside of nested callbacks, it forces you out of your natural way of thinking. Bugs happen when there's a disconnect between how your software is read and how you naturally think.

Like most solutions to software problems, a commonly prescribed approach for making "Callback Hell" easier to consume is to modularize your code.

OK, the function names help us understand what's going on, but is it objectively "better"? Not by much. We've put a band-aid over the readability issue of Callback Hell. The problem still exists that we naturally think sequentially and, even with the extra functions, nested callbacks break us out of that sequential way of thinking.

The next issue of callbacks has to do with inversion of control . When you write a callback, you're assuming that the program you're giving the callback to is responsible and will call it when (and only when) it's supposed to. You're essentially inverting the control of your program over to another program. When you're dealing with libraries like jQuery, lodash, or even vanilla JavaScript, it's safe to assume that the callback function will be invoked at the correct time with the correct arguments. However, for many third-party libraries, callback functions are the interface for how you interact with them. It's entirely plausible that a third party library could, whether on purpose or accidentally, break how they interact with your callback.

Since you're not the one calling criticalFunction , you have 0 control over when and with what argument it's invoked. Most of the time this isn't an issue, but when it is, it's a big one.

Have you ever been to a busy restaurant without a reservation? When this happens, the restaurant needs a way to get back in contact with you when a table opens up. Historically, they'd just take your name and yell it when your table was ready. Then, as naturally occurs, they decided to start getting fancy. One solution was, instead of taking your name, they'd take your number and text you once a table opened up. This allowed you to be out of yelling range but more importantly, it allowed them to target your phone with ads whenever they wanted. Sound familiar? It should! OK, maybe it shouldn't. It's a metaphor for callbacks! Giving your number to a restaurant is just like giving a callback function to a third party service. You expect the restaurant to text you when a table opens up, just like you expect the third party service to invoke your function when and how they said they would. Once your number or callback function is in their hands though, you've lost all control.

Thankfully, there is another solution that exists. One that, by design, allows you to keep all the control. You've probably even experienced it before - it's that little buzzer thing they give you. You know, this one.

Restaurant Buzzer

If you've never used one before, the idea is simple. Instead of taking your name or number, they give you this device. When the device starts buzzing and glowing, your table is ready. You can still do whatever you'd like as you're waiting for your table to open up, but now you don't have to give up anything. In fact, it's the exact opposite. They have to give you something. There is no inversion of control.

The buzzer will always be in one of three different states - pending , fulfilled , or rejected .

pending is the default, initial state. When they give you the buzzer, it's in this state.

fulfilled is the state the buzzer is in when it's flashing and your table is ready.

rejected is the state the buzzer is in when something goes wrong. Maybe the restaurant is about to close or they forgot someone rented out the restaurant for the night.

Again, the important thing to remember is that you, the receiver of the buzzer, have all the control. If the buzzer gets put into fulfilled , you can go to your table. If it gets put into fulfilled and you want to ignore it, cool, you can do that too. If it gets put into rejected , that sucks but you can go somewhere else to eat. If nothing ever happens and it stays in pending , you never get to eat but you're not actually out anything.

Now that you're a master of the restaurant buzzer thingy, let's apply that knowledge to something that matters.

If giving the restaurant your number is like giving them a callback function, receiving the little buzzy thing is like receiving what's called a "Promise".

As always, let's start with why . Why do Promises exist? They exist to make the complexity of making asynchronous requests more manageable. Exactly like the buzzer, a Promise can be in one of three states, pending , fulfilled or rejected . Unlike the buzzer, instead of these states representing the status of a table at a restaurant, they represent the status of an asynchronous request.

If the async request is still ongoing, the Promise will have a status of pending . If the async request was successfully completed, the Promise will change to a status of fulfilled . If the async request failed, the Promise will change to a status of rejected . The buzzer metaphor is pretty spot on, right?

Now that you understand why Promises exist and the different states they can be in, there are three more questions we need to answer.

  • How do you create a Promise?
  • How do you change the status of a promise?
  • How do you listen for when the status of a promise changes?

1) How do you create a Promise?

This one is pretty straight forward. You create a new instance of Promise .

2) How do you change the status of a promise?

The Promise constructor function takes in a single argument, a (callback) function. This function is going to be passed two arguments, resolve and reject .

resolve - a function that allows you to change the status of the promise to fulfilled

reject - a function that allows you to change the status of the promise to rejected .

In the code below, we use setTimeout to wait 2 seconds and then invoke resolve . This will change the status of the promise to fulfilled .

We can see this change in action by logging the promise right after we create it and then again roughly 2 seconds later after resolve has been called.

Notice the promise goes from <pending> to <resolved> .

3) How do you listen for when the status of a promise changes?

In my opinion, this is the most important question. It's cool we know how to create a promise and change its status, but that's worthless if we don't know how to do anything after the status changes.

One thing we haven't talked about yet is what a promise actually is. When you create a new Promise , you're really just creating a plain old JavaScript object. This object can invoke two methods, then , and catch . Here's the key. When the status of the promise changes to fulfilled , the function that was passed to .then will get invoked. When the status of a promise changes to rejected , the function that was passed to .catch will be invoked. What this means is that once you create a promise, you'll pass the function you want to run if the async request is successful to .then . You'll pass the function you want to run if the async request fails to .catch .

Let's take a look at an example. We'll use setTimeout again to change the status of the promise to fulfilled after two seconds (2000 milliseconds).

If you run the code above you'll notice that roughly 2 seconds later, you'll see "Success!" in the console. Again the reason this happens is because of two things. First, when we created the promise, we invoked resolve after ~2000 milliseconds - this changed the status of the promise to fulfilled . Second, we passed the onSuccess function to the promises' .then method. By doing that we told the promise to invoke onSuccess when the status of the promise changed to fulfilled which it did after ~2000 milliseconds.

Now let's pretend something bad happened and we wanted to change the status of the promise to rejected . Instead of calling resolve , we would call reject .

Now this time instead of the onSuccess function being invoked, the onError function will be invoked since we called reject .

Now that you know your way around the Promise API, let's start looking at some real code.

Remember the last async callback example we saw earlier?

Is there any way we could use the Promise API here instead of using callbacks? What if we wrap our AJAX requests inside of a promise? Then we can simply resolve or reject depending on how the request goes. Let's start with getUser .

Nice. Notice that the parameters of getUser have changed. Instead of receiving id , onSuccess , and onFailure , it just receives id . There's no more need for those other two callback functions because we're no longer inverting control. Instead, we use the Promise's resolve and reject functions. resolve will be invoked if the request was successful, reject will be invoked if there was an error.

Next, let's refactor getWeather . We'll follow the same strategy here. Instead of taking in onSuccess and onFailure callback functions, we'll use resolve and reject .

Looking good. Now the last thing we need to update is our click handler. Remember, here's the flow we want to take.

  • Get the user's information from the Github API.
  • Use the user's location to get their weather from the Yahoo Weather API.
  • Update the UI with the user's info and their weather.

Let's start with #1 - getting the user's information from the Github API.

Notice that now instead of getUser taking in two callback functions, it returns us a promise that we can call .then and .catch on. If .then is called, it'll be called with the user's information. If .catch is called, it'll be called with the error.

Next, let's do #2 - Use the user's location to get their weather.

Notice we follow the exact same pattern we did in #1 but now we invoke getWeather passing it the user object we got from userPromise .

Finally, #3 - Update the UI with the user's info and their weather.

Here's the full code you can play around with.

Our new code is better , but there are still some improvements we can make. Before we can make those improvements though, there are two more features of promises you need to be aware of, chaining and passing arguments from resolve to then .

Both .then and .catch will return a new promise. That seems like a small detail but it's important because it means that promises can be chained.

In the example below, we call getPromise which returns us a promise that will resolve in at least 2000 milliseconds. From there, because .then will return a promise, we can continue to chain our .then s together until we throw a new Error which is caught by the .catch method.

Cool, but why is this so important? Remember back in the callback section we talked about one of the downfalls of callbacks being that they force you out of your natural, sequential way of thinking. When you chain promises together, it doesn't force you out of that natural way of thinking because chained promises are sequential. getPromise runs then logA runs then logB runs then... .

Just so you can see one more example, here's a common use case when you use the fetch API. fetch will return you a promise that will resolve with the HTTP response. To get the actual JSON, you'll need to call .json . Because of chaining, we can think about this in a sequential manner.

Now that we know about chaining, let's refactor our getUser / getWeather code from earlier to use it.

It looks much better, but now we're running into an issue. Can you spot it? In the second .then we want to call updateUI . The problem is we need to pass updateUI both the user and the weather . Currently, how we have it set up, we're only receiving the weather , not the user . Somehow we need to figure out a way to make it so the promise that getWeather returns is resolved with both the user and the weather .

Here's the key. resolve is just a function. Any arguments you pass to it will be passed along to the function given to .then . What that means is that inside of getWeather , if we invoke resolve ourself, we can pass to it weather and user . Then, the second .then method in our chain will receive both user and weather as an argument.

You can play around with the final code here

It's in our click handler where you really see the power of promises shine compared to callbacks.

Following that logic feels natural because it's how we're used to thinking, sequentially. getUser then getWeather then update the UI with the data .

Now it's clear that promises drastically increase the readability of our asynchronous code, but is there a way we can make it even better? Assume that you were on the TC39 committee and you had all the power to add new features to the JavaScript language. What steps, if any, would you take to improve this code?

As we've discussed, the code reads pretty nicely. Just as our brains work, it's in a sequential order. One issue that we did run into was that we needed to thread the data ( users ) from the first async request all the way through to the last .then . This wasn't a big deal, but it made us change up our getWeather function to also pass along users . What if we just wrote our asynchronous code the same way which we write our synchronous code? If we did, that problem would go away entirely and it would still read sequentially. Here's an idea.

Well, that would be nice. Our asynchronous code looks exactly like our synchronous code. There's no extra steps our brain needs to take because we're already very familiar with this way of thinking. Sadly, this obviously won't work. As you know, if we were to run the code above, user and weather would both just be promises since that's what getUser and getWeather return. But remember, we're on TC39. We have all the power to add any feature to the language we want. As is, this code would be really tricky to make work. We'd have to somehow teach the JavaScript engine to know the difference between asynchronous function invocations and regular, synchronous function invocations on the fly. Let's add a few keywords to our code to make it easier on the engine.

First, let's add a keyword to the main function itself. This could clue the engine to the fact that inside of this function, we're going to have some asynchronous function invocations. Let's use async for this.

Cool. That seems reasonable. Next let's add another keyword to let the engine know exactly when a function being invoked is asynchronous and is going to return a promise. Let's use await . As in, "Hey engine. This function is asynchronous and returns a promise. Instead of continuing on like you typically do, go ahead and 'await' the eventual value of the promise and return it before continuing". With both of our new async and await keywords in play, our new code will look like this.

Pretty slick. We've invented a reasonable way to have our asynchronous code look and behave as if it were synchronous. Now the next step is to actually convince someone on TC39 that this is a good idea. Lucky for us, as you probably guessed by now, we don't need to do any convincing because this feature is already part of JavaScript and it's called Async/Await .

Don't believe me? Here's our live code now that we've added Async/Await to it. Feel free to play around with it.

async functions return a promise

Now that you've seen the benefit of Async/Await, let's discuss some smaller details that are important to know. First, anytime you add async to a function, that function is going to implicitly return a promise.

Even though getPromise is literally empty, it'll still return a promise since it was an async function.

If the async function returns a value, that value will also get wrapped in a promise. That means you'll have to use .then to access it.

await without async is bad

If you try to use the await keyword inside of a function that isn't async , you'll get an error.

Here's how I think about it. When you add async to a function it does two things. It makes it so the function itself returns (or wraps what gets returned in) a promise and makes it so you can use await inside of it.

Error Handling

You may have noticed we cheated a little bit. In our original code we had a way to catch any errors using .catch . When we switched to Async/Await, we removed that code. With Async/Await, the most common approach is to wrap your code in a try/catch block to be able to catch the error.

Before you leave

I know, another newsletter pitch - but hear me out. Most JavaScript newsletters are terrible. When’s the last time you actually looked forward to getting one? Even worse, when’s the last time you actually read one? We wanted to change that.

We call it Bytes , but others call it their favorite newsletter .

Delivered to 216,409 developers every Monday and Thursday

Avatar for @sduduzo_g

@ sduduzo_g

This is the first ever newsletter that I open a music playlist for and maximize my browser window just to read it in peace. Kudos to @uidotdev for great weekly content.

Avatar for @flybayer

Brandon Bayer

The Bytes newsletter is a work of art! It’s the only dev newsletter I’m subscribed too. They somehow take semi boring stuff and infuse it with just the right amount of comedy to make you chuckle.

Avatar for @johnhawly

John Hawley

@ johnhawly

Bytes has been my favorite newsletter since its inception. It’s my favorite thing I look forward to on Mondays. Goes great with a hot cup of coffee!

Avatar for @garrettgreen

Garrett Green

@ garrettgreen

I subscribe to A LOT of dev (especially JS/TS/Node) newsletters and Bytes by @uidotdev is always such a welcomed, enjoyable change of pace to most (funny, lighthearted, etc) but still comprehensive/useful.

Avatar for @mhashim6_

@ mhashim6_

Literally the only newsletter I’m waiting for every week.

Avatar for @graysonhicks

Grayson Hicks

@ graysonhicks

Bytes is the developer newsletter I most look forward to each week. Great balance of content and context! Thanks @uidotdev.

Avatar for @mitchellbwright

Mitchell Wright

@ mitchellbwright

I know I’ve said it before, but @tylermcginnis doesn’t miss with the Bytes email. If you’re a developer, you really need to subscribe

Avatar for @aspittel

Ali Spittel

Can I just say that I giggle every time I get the @uidotdev email each week? You should definitely subscribe.

Avatar for @thefinnomenon

@ thefinnomenon

Every JavaScript programmer should be subscribed to the newsletter from @uidotdev. Not only do they manage to succinctly cover the hot news in the JavaScript world for the week but it they manage to add a refreshing humor to it all.

  • Skip to primary navigation
  • Skip to content

Call us +1 415 416 0800

Metana

  • Solidity Bootcamp Hot 🔥

Web3 Solidity Bootcamp

The most advanced Solidity curriculum on the internet

Full Stack Web3 Beginner Bootcamp

Starting off with web development and seamlessly integrating web3 development

Web3 Rust Bootcamp

Become an expert Solana blockchain developer with one course!

Coding + Career Growth

Software engineering bootcamp.

Become a Software Engineer - Balance everyday life commitments & launch your coding career in as little as 16 weeks

Metana's JobCamp™️

Learn to make a lasting first impressions, network effectively & search for jobs with confidence.

javascript await without assignment

Rated the Best

Ranked as the industry's premier Web3 bootcamp with a stellar 4.8/5 star rating on Course Report.

  • Metana’s Job Guarantee

Metana Bootcamps

  • Full Stack Web3 Bootcamp
  • Rust Bootcamp
  • Cybersecurity Bootcamp
  • AI & Machine Learning Bootcamp
  • Data Analytics Bootcamp
  • Data Science Bootcamp
  • Full Stack Bootcamp
  • Refer a Friend
  • Withdrawal and Refund Policy

[email protected]

Table of Contents

Asynchronous javascript: callbacks, promises, and async/await, metana editorial.

  • May 9, 2024

Best way to understand asynchronous JavaScrip t is to imagine you’re juggling. You can keep a few balls in the air at once, but eventually, you’ll need to catch one before throwing another. That’s how traditional JavaScript works – it can only handle one task at a time. But what if you want your program to feel more responsive, handling multiple tasks without everything grinding to a halt? That’s where asynchronous JavaScript comes in.

Synchronous vs Asynchronous

Before diving into Callbacks, Promises, and Async/Await, let’s establish the fundamental difference between synchronous and asynchronous programming. Imagine you’re juggling:

  • Synchronous: This is like juggling one ball at a time. Your program executes instructions sequentially, waiting for each operation to complete before moving on to the next. It’s simple to understand but can become sluggish if tasks take time (like fetching data from a server).
  • Asynchronous: This is like juggling multiple balls. Your program can initiate multiple operations concurrently, without waiting for each one to finish. It’s ideal for keeping your application responsive while handling long-running tasks. Think of it as queuing up the balls you want to juggle – you throw one, then another, but they can all be in the air at different stages.

Here’s a table summarizing the key differences:

Execution FlowSequential, one task at a timeConcurrent, multiple tasks can be in progress
WaitingWaits for each operation to complete before moving onDoesn’t wait, can move on to other tasks while waiting for asynchronous operations to finish
ResponsivenessMay become unresponsive if tasks take timeStays responsive even with long-running tasks
ComplexitySimpler to understand and write initiallyCan be more complex to manage due to concurrency

Choosing Between Synchronous and Asynchronous:

The choice between synchronous and asynchronous programming depends on your application’s needs. Synchronous is suitable for simple tasks or when immediate results are crucial. Asynchronous is ideal for building responsive web applications that can handle user interactions and data fetching without blocking the UI. To achieve this asynchronous magic, JavaScript employs three key concepts: Callbacks, Promises, and Async/Await.

Callbacks are the original way to handle asynchronous operations in JavaScript. Think of them as your juggling assistant. You throw a ball (initiate an asynchronous task) and tell your assistant (the callback function) to catch it (handle the result) when it comes down. Here’s how it works:

  • Initiate the Asynchronous Operation: You call a function that takes some time to complete, like fetching data from a server.
  • Pass the Callback Function: You provide another function (the callback) that you want to be executed when the asynchronous operation finishes.
  • The Waiting Game: The main program continues executing other tasks while the asynchronous operation is ongoing.
  • The Catch: Once the asynchronous operation finishes, it “calls back” – it executes the callback function you provided, passing the result (data or error) as an argument.

Example: Fetching Data with a Callback

Imagine fetching a user’s profile information from an API. Here’s a simplified example using a callback:

This code defines a getUserProfile function that takes a user ID and a callback function as arguments. It simulates an asynchronous operation (like a network request) using setTimeout and then calls the provided callback function with the user profile data. The main program continues by logging “Fetching user profile…” and then defines another function that will be called back with the profile information.

Callback Hell

Callbacks can be a good starting point, but things can get messy when you have multiple asynchronous operations nested within each other. This creates a chain of callbacks, often referred to as “callback hell,” where the code becomes difficult to read and maintain. Imagine juggling multiple balls and having to instruct an assistant for each one, with each assistant needing further instructions!

Promises offer a more structured approach to handling asynchronous operations. They act like a placeholder for the eventual result (or error) of an asynchronous task. Here’s the breakdown: Instead of relying on an assistant to catch the ball, you now have a box (the promise) that will hold the ball (the result) once it comes down.

  • Creating the Promise: The asynchronous function creates a promise object. This object represents the eventual completion (or failure) of the operation.
  • Promise States: A promise can be in three states: pending (operation in progress), fulfilled (operation successful with a result), or rejected (operation failed with an error).
  • Consuming the Promise: You use the then and catch methods on the promise object to specify what code to run when the promise is fulfilled (gets the result) or rejected (encounters an error).

We explored Callbacks and how they can lead to “callback hell.” Promises offer a cleaner alternative by providing a structured way to handle asynchronous operations. Let’s dive deeper into Promises and how they are used in conjunction with then and catch methods.

Example: Fetching Data with a Promise

Let’s revisit the user profile example using a promise:

In this example, the getUserProfile function returns a new promise. Inside the promise, we use setTimeout to simulate an asynchronous operation (like a network request). Once the delay is complete, we either call resolve with the user profile data if successful, or reject with an error if there’s an issue.

The .then method is then used to specify what to do with the user profile data once it’s available. The .catch method ensures we handle any potential errors during the asynchronous operation.

Chaining Promises

Promises allow you to chain asynchronous operations one after another. Imagine juggling multiple balls, but instead of needing an assistant for each one, you can throw one ball, then another, knowing that each promise will hold the result until you’re ready to use it.

Here’s how promise chaining works:

  • Create the First Promise: You call an asynchronous function that returns a promise representing the first operation.
  • Chain with then : You use the then method on the first promise to specify a function to be executed when the first promise is fulfilled (resolved with a result).
  • Return a New Promise (Optional): Inside the then function, you can optionally return another promise to chain further asynchronous operations.
  • Handle Subsequent Results: Subsequent then methods will receive the result from the previous promise in the chain.

Example: Chaining Promises for User Details and Posts

Let’s expand our example to fetch a user’s profile and then their posts using promises:

In this example, we first call getUserProfile and chain a then method to fetch the user’s posts using the profile.id retrieved in the first step. Each then method receives the result from the previous promise, allowing us to handle the data flow smoothly.

Error Handling with catch

The catch method is used to handle errors that may occur during any point in the promise chain. It’s crucial to include catch to prevent unhandled exceptions and ensure your application remains responsive.

Async/Await

Async/Await is a syntactic sugar built on top of Promises that makes asynchronous code look more synchronous. It provides a cleaner way to write asynchronous code that resembles synchronous code flow. Here’s the juggling analogy: Imagine you have special gloves that allow you to throw and catch multiple balls simultaneously, without needing to think about the order or wait for each one to come down before throwing the next.

  • Async Function Declaration: You declare a function using the async keyword, indicating it will involve asynchronous operations.
  • await Keyword: Inside the async function, you use the await keyword before a promise. This pauses the execution of the async function until the promise resolves (or rejects), and then the returned value from the promise is available for further use.

Example: Fetching Data with Async/Await

Let’s revisit the user profile example using async/await:

This code defines two asynchronous functions: getUserProfile and main. getUserProfile simulates fetching user data (here, Alice’s information) using a promise and await. The main function calls getUserProfile and uses await to wait for the data before logging the user profile to the console. It also includes error handling with try…catch to gracefully handle any issues during data retrieval.

Error Handling with try…catch in Async/Await

Similar to promises, Async/Await allows error handling using a try…catch block. You can wrap the asynchronous operations (using await) within a try block and define a catch block to handle any potential errors.

In this example, the try…catch block ensures that any errors thrown during the promise or within the async function are caught and handled appropriately.

Handling Multiple Asynchronous Operations with Async/Await

Async/Await allows you to manage multiple asynchronous operations concurrently. Here are two common approaches:

  • Sequential Execution: You can use await sequentially with multiple promises to execute them one after another, similar to promise chaining.
  • Parallel Execution (Using Promise.all ): For truly parallel execution, you can leverage Promise.all which takes an iterable of promises and returns a single promise that resolves when all the individual promises resolve, or rejects if any of them reject.

Best Practices for Asynchronous JavaScript

Here are some key practices to keep in mind when working with asynchronous JavaScript:

  • Error Handling: Always include proper error handling using catch or try…catch blocks to ensure your application remains responsive and gracefully handles potential issues.
  • Readability: Use clear variable names and comments to explain the asynchronous flow of your code, especially when dealing with complex operations or nested promises.
  • Consider Performance: While Async/Await simplifies code, be mindful of potential performance implications, especially when dealing with a large number of concurrent asynchronous operations. Consider techniques like throttling or debouncing for UI updates.
  • Testing: Thoroughly test your asynchronous code to ensure it behaves as expected under various conditions, including handling failures and edge cases.

Mastering asynchronous JavaScript is essential for building modern web applications that are responsive, performant, and user-friendly. Callbacks, Promises, and Async/Await offer different approaches to managing asynchronous operations. Choose the approach that best suits your project’s needs and complexity, while adhering to best practices for error handling, readability, and performance. With a solid understanding of asynchronous JavaScript, you can create dynamic and engaging web experiences!

What is asynchronous JavaScript?

  • Asynchronous JavaScript allows tasks to run in the background without blocking other operations, enhancing web application performance.

How do callbacks work in JavaScript?

  • Callbacks are functions passed as arguments to other functions to execute after a previous function has finished, managing asynchronous operations.

What are JavaScript promises?

  • Promises in JavaScript represent a value that may be available now, later, or never, facilitating error handling and asynchronous operation chaining.

What is the purpose of async/await in JavaScript?

  • The async/await syntax in JavaScript provides a cleaner, more readable structure for handling promises and simplifying asynchronous code.

How can asynchronous JavaScript improve web application performance?

  • By handling operations in the background and not blocking the main execution thread, asynchronous JavaScript can significantly speed up response times.

What are the best practices for using asynchronous JavaScript?

  • Key practices include proper error handling, avoiding callback hell through modularization, and leveraging promises and async/await for cleaner code.

Can asynchronous JavaScript methods be combined?

  • Yes, developers often mix callbacks, promises, and async/await to optimize performance and improve code readability.

What are some common pitfalls in using asynchronous JavaScript?

  • Common issues include callback hell, promise mishandling, and underestimating the complexity of async/await patterns.

How does asynchronous JavaScript affect server-side applications?

  • On the server-side, particularly with Node.js, asynchronous JavaScript can handle multiple requests efficiently without blocking the server.

What resources can help beginners learn asynchronous JavaScript?

  • Online tutorials, documentation like MDN, coding bootcamps, and community forums are great starting points to understand and implement asynchronous JavaScript.

javascript await without assignment

Metana Guarantees a Job 💼

Plus risk free 2-week refund policy ✨.

You’re guaranteed a new job in web3—or you’ll get a full tuition refund. We also offer a hassle-free two-week refund policy. If you’re not satisfied with your purchase for any reason, you can request a refund, no questions asked.

The most advanced Solidity curriculum on the internet!

  • Prior coding experience required
  • 1-on-1 mentorship
  • Expert code reviews
  • Coaching & career services

Learn foundational principles while gaining hands-on experience with Ethereum, DeFi, and Solidity.

  • Beginner - Zero to Hero
  • Your very own personal support tutor

You may also like

Boost web speed fast: essential javascript minifier tips.

javascript await without assignment

Javascript Events: Beginners’ Guide

Plus risk free 2-week refund policy, events by metana.

Dive into the exciting world of Web3 with us as we explore cutting-edge technical topics, provide valuable insights into the job market landscape, and offer guidance on securing lucrative positions in Web3.

Start Your Application

Secure your spot now. Spots are limited, and we accept qualified applicants on a first come, first served basis..

The application is free and takes just 3 minutes to complete.

What is included in the course?

Expert-curated curriculum, weekly 1:1 video calls with your mentor, weekly group mentoring calls, on-demand mentor support, portfolio reviews by design hiring managers, resume & linkedin profile reviews, active online student community, 1:1 and group career coaching calls, access to our employer network, job guarantee.

Adding {{itemName}} to cart

Added {{itemName}} to cart

Async/Await without Try/Catch Block in JavaScript

When you have learned about JavaScript promises for the first time, you learned about the promise's methods then and catch. While the former's callback function is called whenever a JavaScript promise resolves successfully, the latter is used for error handling:

Eventually you have learned about async/await in JavaScript as alternative to a JavaScript promise's then and catch methods:

The shift from then/catch to async/await was a pretty powerful one, because suddenly you would be able to read your code in a synchronous way again. Every line happening after the await statement has to wait until the promise resolves. In addition, writing code like this felt way more concise. But then there is the error handling for async/await with a try/catch block:

This broke all the conciseness from async/await again, because instead of having asynchronous callbacks in then/catch blocks, we ended up with a try/catch block surrounding everything. So what if you could get the best out of both worlds?

This works, the only flaw here is that in a case of an error all the code after the await statement will still execute. We would have to guard it with a condition, but only if you would need to avoid this behavior:

We could also return the error and do the error handling in the if block:

Now you ended up without a bulky try/catch block but a guarding if clause in case an error (or nothing) is returned from your JavaScript promise. Whether this makes things cleaner than using a try/catch block is up to you. Maybe it is for certain scenarios, however, I have learned that going with the standard implementation of try/catch is preferred when working with other developers on one code base to establish a common sense.

Keep reading about   JavaScript

javascript await without assignment

Custom Errors in JavaScript

There are two error handling scenarios in JavaScript. Either an error is thrown from a third-party (e.g. library, database, API) or you want to throw an error yourself. While you have the error at…

javascript await without assignment

JavaScript Naming Conventions

A JavaScript naming conventions introduction by example -- which gives you the common sense when it comes to naming variables, functions, classes or components in JavaScript. No one is enforcing these…

javascript await without assignment

The Road to React

Learn React by building real world applications. No setup configuration. No tooling. Plain React in 200+ pages of learning material. Learn React like 50.000+ readers .

Never miss an article about web development and JavaScript.

Join 50.000+ Developers

Learn Web Development

Learn JavaScript

Access Tutorials, eBooks and Courses

Personal Development as a Software Engineer

youtube logo

How to use Async Await in JavaScript

There are many ways javascript provides us with the ability to make it behave like an asynchronous language. one of them is with the async-await clause..

By Ashay Mandwarya on 2019-01-10

Graphic that says JavaScript Async/Await

JavaScript is a bit like The Faceless Men of the programming world.

It can be Asynchronous. It can be Functional. It can be Object-oriented. It can be Client-side. It can be Server-side. The list goes on.

image

This article will focus on Asynchronous JavaScript.

But wait, JavaScript is a synchronous language!

This means only one operation can be carried out at a time. But that's not the entire picture here. There are many ways JavaScript provides us with the ability to make it behave like an asynchronous language. One of them is with the Async-Await clause.

What is async-await?

Async and Await are extensions of promises. If you are not clear with the concepts of Promise, you can refer my previous post  How to write Promises in JavaScript .

image

Async functions enable us to write promise based code as if it were synchronous, but without blocking the execution thread. It operates asynchronously via the event-loop. Async functions will always return a value. Using  async  simply implies that a promise will be returned, and if a  promise is not returned, JavaScript automatically wraps it in a resolved  promise  with its value.

Running the above code gives the alert output as 27, it means that a  promise  was returned, otherwise the  .then()  method simply would not be possible.

The await operator is used to wait for a Promise. It can be used inside an Async block only. The keyword Await makes JavaScript wait until the promise returns a result. It has to be noted that it only makes the  async  function block wait and not the whole program execution.

The code block below shows the use of Async Await together.

Things to remember when using Async Await

We can't use the await keyword inside of regular functions..

To make the above function work properly, we need to add  async before the function  firstAsync();

Async Await makes execution sequential

Not necessarily a bad thing, but having paralleled execution is much much faster.

For example:

The above takes 100ms to complete, not a huge amount of time but still slow.

This is because it is happening in sequence. Two promises are returned, both of which takes 50ms to complete. The second promise executes only after the first promise is resolved. This is not a good practice, as large requests can be very time consuming. We have to make the execution parallel.

That can be achieved by using  Promise.all() .

According to MDN: "The  Promise.all()  method returns a single  Promise  that resolves when all of the promises passed as an iterable have resolved or when the iterable contains no promises. It rejects with the reason of the first promise that rejects."

Promise.all()

The  promise.all()  function resolves when all the promises inside the iterable have been resolved and then returns the result.

Another method:

Async Await is very powerful but they come with caveats. But if we use them properly, they help to make our code very readable and efficient.

I hope you have learned something new! If you found this article useful, be sure to share, follow and support!

If you're looking for Java homework help , you've come to the right place! Our team of experienced programmers can help with async coding assignments, programming projects and more.

Continue Learning

8 on scroll animation javascript libraries you can consider.

Create awesome scroll-triggered animations on elements on your website.

A guide to creating a React app without create-react-app

Creating a React App from scratch

Best Tool for Web Scraping: BeautifulSoup vs. Regex vs. Advanced Web Scrapers

BeautifulSoup, Regular Expressions, or an advanced web scraper - which is the best tool for web scraping? A deep dive into web scraping using each.

Are JavaScript for loops better than filter() and forEach?()

Over the last few years, the methods in ES6 like filter(), forEach() and map() have been ever so popular. But are they actually better?

Array Destructuring in JavaScript: A Comprehensive Beginner's Guide

Closing a window with javascript.

What works, what doesn't, in a nutshell

  • recommendations

javascript await without assignment

  • Async/Await
  • @code_barbarian
  • TCB Facebook

Most Popular Articles

  • Common Async/Await Design Patterns in Node.js
  • Unhandled Promise Rejections in Node.js
  • Using Async/Await with Mocha, Express, and Mongoose
  • Write Your Own Node.js Promise Library from Scratch
  • The 80/20 Guide to Express Error Handling

javascript await without assignment

The 80/20 Guide to ES2015 Generators

The 80/20 Guide to Async/Await in Node.js

Arguably the biggest new feature in Node.js 7.6.0 is that the much awaited async function keyword is now available without a flag . Callback hell and promise hell are now in the past. But, like Uncle Ben always reminded us , with great power comes great responsibility, and async/await gives you a lot of new and exciting ways to shoot yourself in the foot. You still need to handle errors and be aware of the async nature of your code, otherwise you'll inevitably be complaining about "async/await hell" in 6 months.

All code in this article was tested on node.js 7.6.0. It will not work on earlier versions of node. Node.js 7.x is an odd-numbered Node.js release, which means it is scheduled to be deprecated in June 2017, so I wouldn't recommend using it in production.

Hello, World

Here's a "Hello, World" example of using async/await:

You can run this node script like any other, without any transpilers, and it will print out "Hello, World!" after approximately 1 second. This is how you can implement JavaScript sleep with async/await.

Async functions are based entirely on promises . You should always await on a promise. Using await on a non-promise won't do anything:

You don't need to use native Node.js promises with await . Bluebird or any other promise lib should work. In general, using await with any object that has a then() function will work:

There is one major restriction for using await : you must use await within a function that's declared async . The below code will result in a SyntaxError .

Furthermore, await must not be in a closure embedded in an async function, unless the closure is also an async function. The below code also results in a SyntaxError :

Another important detail to remember about async functions is that async functions return promises:

This means that you can await on the result of an async function.

Return Values and Exceptions

A promise can either resolve to a value or reject with an error. Async/await lets you handle these cases with synchronous operators: assignment for resolved values, and try/catch for exceptions. The return value of await is the value that the promise resolves to:

In an async function, you can use try/catch to catch promise rejections. In other words, asynchronous promise rejections behave like synchronous errors:

Using try/catch as an error handling mechanism is powerful because it enables you to handle synchronous errors and asynchronous errors with a single syntax. In callback land you'd often have to wrap your async calls in a try/catch as well as handling the error callback parameter.

Loops and Conditionals

The number one killer feature of async/await is that you can write async code using if statements, for loops, and all the other synchronous constructs that you had to swear off of when using callbacks. You don't need any flow control libraries with async/await, you just use conditionals and loops. Here's an example using a for loop:

And an example using an if statement:

Remember It's Asynchronous

One cute JavaScript interview question I used to ask was what would the below code print out?

Asynchronous code is confusing, and async/await makes it easier to write asyncronous code but doesn't change the nature of asynchronous code. Just because async functions look synchronous doesn't mean they are:

Error Handling

Remember that you can only use await within an async function, and async functions return promises. This means that somewhere in your code you're going to have to handle errors. Async/await gives you a powerful mechanism for aggregating errors: all errors that occur in the async function, synchronous or asynchronous, are bubbled up as a promise rejection. However, it's up to you to handle the error. Here's another interesting article on the topic of handling promise rejections with async/await .

Let's say you want to use async/await with the Express web framework . The naive way of using async functions with Express works in the most basic case:

So we're done, right? Wrong . What happens if you throw an exception in the handler function?

Express will hang forever, the server won't crash, and the only indication of an error would be an unhandled promise rejection warning.

Since await treats promise rejections as exceptions, unless you try/catch around await the rejection will cause the entire function to stop executing. The below handler function will also hang with an unhandled promise rejection warning.

javascript await without assignment

The single most important takeaway from this article is that async functions return a promise. Async/await gives you the ability to build sophisticated async logic with loops, conditionals, and try/catch , but in the end it packages all this logic into a single promise. If you see async/await code that doesn't include any .catch() calls, odds are that code is missing some error cases. Here's a better way of handling async functions with Express:

The safeHandler function chains .catch() onto the promise that the async handler function returns. This ensures that your server sends an HTTP response, even if handler errors out. If calling safeHandler on every request handler seems cumbersome, there are numerous alternatives, like using observables or ramda .

Async/Await vs Co/Yield

The co library uses ES6 generators to get functionality similar to async/await. For example, here's how the safeHandler code example would look with co/yield:

As a matter of fact, you can replace every async function(params) {} in this article with function(params) { return co(function*() {}) } and await with yield and all the examples will still work.

The upside of using co is that co works without any transpilation in Node.js 4.x and 6.x. The EOL of 4.x and 6.x is in 2018 and 2019, respectively, so these releases are more stable than Node.js 7.x. Until Node.js 8 is released (tentatively scheduled for April 2017) there's no LTS version of Node.js that supports async/await without transpilers. Co also enjoys better browser support, and every transpiler for async/await that I know of compiles down to using generators. If you're interested in really mastering co and generators, check out my ebook, The 80/20 Guide to ES2015 Generators , which walks you through writing your own co from scratch.

Async/await has numerous advantages, most notably readable stack traces. Let's compare the stack traces of using co vs using async/await with the Express example:

So async/await has better stack traces and lets you construct promises using the built-in loops and conditionals that you already know, so download Node.js 7.6 and give it a shot!

Looking to become fluent in async/await? My new ebook, Mastering Async/Await, is designed to give you an integrated understanding of async/await fundamentals and how async/await fits in the JavaScript ecosystem in a few hours. Get your copy!

javascript await without assignment

  • Skip to main content
  • Skip to search
  • Skip to select language
  • Sign up for free

SyntaxError: await is only valid in async functions, async generators and modules

The JavaScript exception "await is only valid in async functions, async generators and modules" occurs when an await expression is used outside of async functions or modules or other async contexts.

SyntaxError .

What went wrong?

JavaScript execution is never blocking: an await can never block the execution of the program. Instead, it pauses the execution of the surrounding async task, while allowing other tasks to continue running. Therefore, await cannot be used in sync tasks, such as functions, generator functions, or top level of scripts. It is not always apparent whether the current file is a script or a module — see the Modules guide for more information.

Top-level await

You cannot use await at the top level of a script:

Instead, make the script a module:

Async callbacks

You cannot use await in a sync callback:

Instead, make the callback async. See more explanation in the Using promises guide .

  • Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand
  • OverflowAI GenAI features for Teams
  • OverflowAPI Train & fine-tune LLMs
  • Labs The future of collective knowledge sharing
  • About the company Visit the blog

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

Why doesn't the code after await run right away? Isn't it supposed to be non-blocking?

I have a hard time understanding how async and await works behind the scenes. I know we have promises which make our non blocking code by using the "then" function we can place all the work we need to do after the promise is resolved. and the work we want to do parallel to promise we just write it outside our then function. Hence the code becomes non blocking. However i don't understand how the async await makes non-blocking code.

See the above code. I cannot move forward until the API call is resolved. If it makes my code blocking code, how is it any better then promises? Or is there something I missed about async and await ? Where do i put my code that is not dependent to the await call? so it can keep on working without await holding the execution?

I am adding a Promise code that i would like to replicate in an async await example.

  • async-await
  • es6-promise
  • ecmascript-2017

peterh's user avatar

  • AFAIK, await requires that the thing it's awaiting be a promise. So it's not really a either/or. –  Paul Commented Apr 9, 2017 at 3:01
  • It's sort of as if the lines after your "until it resolves" comment are inside a .then() . And your whole function is itself async, so whatever calls it doesn't have to wait for it. –  nnnnnn Commented Apr 9, 2017 at 3:06
  • @Paul it also converts the expression in promise if it is not a promise. that what i read in a blog –  Rohail Najam Commented Apr 9, 2017 at 3:07
  • @nnnnnn Yes. its like i put that in .then(). but how do i put it outside a then() in async await scenario –  Rohail Najam Commented Apr 9, 2017 at 3:09
  • @RohailNajam Right, my point was about async calls, though. Using a function that expects a callback in place of that promise would not work. –  Paul Commented Apr 9, 2017 at 3:12

Just as its name implies, the await keyword will cause the function to "wait" until the corresponding promise resolves before executing the next line. The whole point of await is to provide a way to wait for an asynchronous operation to complete before continuing.

The difference between this and blocking code is that the world outside the function can continue executing while the function is waiting for the asynchronous operations to finish.

async and await are just syntactic sugar on top of promises. They allow you to write code that looks a lot like ordinary synchronous code even though it uses promises under the covers. If we translated your example there to something that explicitly worked with the promises, it would look something like:

As we can see here, the let result = 2 + 2; line is inside a .then() handler, which means it's not going to execute until myAPICall() has resolved. It's the same when you use await . await just abstracts away the .then() for you.

One thing to bear in mind (and I think the point you're looking for) is that you don't have to use await right away. If you wrote your function like this, then you could execute your let result = 2 + 2; line right away:

const timeout = seconds => new Promise(res => setTimeout(res, seconds * 1000)); function myAPICall() { // simulate 1 second wait time return timeout(1).then(() => 'success'); } async function myAsyncFunction() { try { console.log('starting'); // just starting the API call and storing the promise for now. not waiting yet let dataP = myAPICall('https://jsonplaceholder.typicode.com/posts/1'); let result = 2 + 2; // Executes right away console.log('result', result); // wait now let data = await dataP; // Executes after one second console.log('data', data); return data; } catch (ex) { return ex; } } myAsyncFunction();

After some clarification, I can see that what you really wanted to know about is how to avoid having to wait for two async operations one by one and instead have them execute in parallel. Indeed, if you use one await after the other, the second won't start executing until the first has finished:

const timeout = seconds => new Promise(res => setTimeout(res, seconds * 1000)); function myAPICall() { // simulate 1 second wait time return timeout(1).then(() => 'success'); } async function myAsyncFunction() { try { console.log('starting'); let data1 = await myAPICall('https://jsonplaceholder.typicode.com/posts/1'); // logs after one second console.log('data1', data1); let data2 = await myAPICall('https://jsonplaceholder.typicode.com/posts/2'); // logs after one more second console.log('data2', data2); } catch (ex) { return ex; } } myAsyncFunction();

To avoid this, what you can do is start both async operations by executing them without awaiting them, assigning their promises to some variables. Then you can await both promises:

const timeout = seconds => new Promise(res => setTimeout(res, seconds * 1000)); function myAPICall() { // simulate 1 second wait time return timeout(1).then(() => 'success'); } async function myAsyncFunction() { try { console.log('starting'); // both lines execute right away let dataP1 = myAPICall('https://jsonplaceholder.typicode.com/posts/1'); let dataP2 = myAPICall('https://jsonplaceholder.typicode.com/posts/2'); let data1 = await dataP1; let data2 = await dataP2; // logs after one second console.log('data1', data1); console.log('data2', data2); } catch (ex) { return ex; } } myAsyncFunction();

One alternative way to do this is to use Promise.all() with some array decomposition:

const timeout = seconds => new Promise(res => setTimeout(res, seconds * 1000)); function myAPICall() { // simulate 1 second wait time return timeout(1).then(() => 'success'); } async function myAsyncFunction() { try { console.log('starting'); // both myAPICall invocations execute right away const [data1, data2] = await Promise.all([ myAPICall('https://jsonplaceholder.typicode.com/posts/1'), myAPICall('https://jsonplaceholder.typicode.com/posts/2'), ]); // logs after one second console.log('data1', data1); console.log('data2', data2); } catch (ex) { return ex; } } myAsyncFunction();

JLRishe's user avatar

  • I understand this. what my point is that if we want to run anything in parallel to this api call we will just put it next to the then function like i did in my edited question. How will i achieve this "Parallelism" in async await –  Rohail Najam Commented Apr 9, 2017 at 3:20
  • @RohailNajam Please see my update. You can "start" as many promises in parallel as you want. Once you use await , the function will start waiting on their result. –  JLRishe Commented Apr 9, 2017 at 3:25
  • 2 @RohailNajam Yes, that's correct. I've modified my answer to show how you can use array decomposition to split it into its respective values. –  JLRishe Commented Apr 9, 2017 at 11:37
  • 1 "the world outside the function will continue to go on executing while this function is doing its thing" The "world outside" will go on while the function is not doing anything. –  a better oliver Commented Apr 12, 2017 at 8:14
  • 1 @zeroflagL A nitpick, indeed, but fair enough. I've fixed the wording. –  JLRishe Commented Nov 3, 2017 at 15:28

Your Answer

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged javascript async-await es6-promise ecmascript-2017 or ask your own question .

  • Featured on Meta
  • Upcoming initiatives on Stack Overflow and across the Stack Exchange network...
  • Announcing a change to the data-dump process

Hot Network Questions

  • A Java class for checking whether a white king is under checkmate
  • Confusion about Mathematical Induction
  • What kind of useless Stack Exchange Site is this?
  • No module named 'setuptools.command.test'
  • The relevance of knowing "just facts"
  • Switch activated by stepper motor unintentionally
  • Is it safer to sarcastically say "This is not a scam" than honestly say "This is a scam"?
  • Modify Rules with new patterns
  • How can I link a Windows domain account to a SQL Server account?
  • Why try to explain the unexplainable?
  • Why are quadratic residues more interesting than cubic residues?
  • Can I remove these truss supports?
  • What is the best way to close this small gap in the tile?
  • Is doping still a thing in pro cycling?
  • Wizz Air Non Eu citizen check in
  • How can life which cannot live on the surface of a planet naturally reach the supermajority of the planet's caves?
  • Intuition behind constructions of good qLDPC codes
  • Size of apartments in Sweden
  • How Does Our Current Understanding of QFT Affect Chemistry and Biology?
  • Windows 11 erases GRUB data making booting into Linux painful
  • How many times did Moses strike the rock?
  • Which Jesus died or in what sense did Jesus ("God") die for our sins
  • What type of outlet has four vertical slots and how can I modernize it?
  • Plastic guides in Shimano brake levers

javascript await without assignment

IMAGES

  1. NodeJS : Does await guarantee execution order without assignment in

    javascript await without assignment

  2. HTML : Is it possible to use await without async in Js

    javascript await without assignment

  3. How to use async/await to properly link multiple functions in Javascript

    javascript await without assignment

  4. JavaScript Async Await Explained With Example

    javascript await without assignment

  5. Async/Await in JavaScript: Understanding and Implementing Asynchronous Code

    javascript await without assignment

  6. JavaScript Promises and Async/Await Cheatsheet

    javascript await without assignment

VIDEO

  1. DEADLY AMBUSH

  2. Урок 8. JavaScript. Как работает Async, Await. Работа с сервером c fetch

  3. 30 gündə JavaScript. DƏRS 11 (Destructuring, Spreading)

  4. How To Fetch HTML From API In JavaScript Using HMPL.js?

  5. Use Promise.all to Await Multiple Promises in Parallel in Javascript 💡

  6. Asynchronous Programing In JavaScript

COMMENTS

  1. Does await guarantee execution order without assignment in JavaScript?

    Yes they are exactly the same, it's more or less syntactic sugar. The await causes execution to pause until the awaited Promise is resolved. See Javascript async the section on rewriting a promise chain for more information. the thing: this section misses the case without assignment.

  2. await

    The await operator is used to wait for a Promise and get its fulfillment value. It can only be used inside an async function or at the top level of a module.

  3. javascript

    What is occurring when an assignment to an await Promise is used versus simply using await without assignment? Taking the code below: const getSomething = async () => { let todos = null; await

  4. Async/await

    There's a special syntax to work with promises in a more comfortable fashion, called "async/await". It's surprisingly easy to understand and use.

  5. How to Use Async/Await in JavaScript

    Hello friends! In this article, I'm going to show you how to use the "async/await" special syntax when handling JavaScript Promises.

  6. A Beginner's Guide to JavaScript async/await, with Examples

    The async and await keywords in JavaScript provide a modern syntax to help us handle asynchronous operations. In this tutorial, we'll take an in-depth look at how to use async/await to master ...

  7. JavaScript Async / Await: Asynchronous JavaScript

    In this tutorial, you will learn a new syntax to write asynchronous code by using JavaScript async/ await keywords.

  8. How to Use Async/Await in JavaScript with Example JS Code

    In this tutorial, we are going to learn how to use Async/Await in JavaScript. But before we get there, we should understand a few topics like: 1. Event loops 2. Callbacks 3. Promises What are Event Loops in JavaScript? Event loops are one of the most important

  9. Async/Await in JavaScript: The Ultimate Guide

    async/await is a powerful feature in JavaScript that simplifies asynchronous programming and improves code readability. By using async/await with promises and the try/catch statement, you can write more efficient and error-resistant code.

  10. JavaScript: Promise or async-await? Async without await, Await ...

    Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise. Then, the await keyword: await only works inside async functions. Causes async function execution to pause until a promise is settled.

  11. Async JavaScript: From Callbacks, to Promises, to Async/Await

    In this post you'll learn about the historical context as well as the pros and cons behind the three most popular JavaScript async patterns - Callbacks, Promises, and Async/Await.

  12. for await...of

    The for await...of statement creates a loop iterating over async iterable objects as well as sync iterables. This statement can only be used in contexts where await can be used, which includes inside an async function body and in a module.

  13. Using promises

    async / await builds on promises — for example, doSomething() is the same function as before, so there's minimal refactoring needed to change from promises to async / await. You can read more about the async / await syntax in the async functions and await references.

  14. Asynchronous JavaScript: Callbacks, Promises, and Async/Await

    Discover how asynchronous JavaScript improves performance using callbacks, promises, and async/await. Essential tips for efficient coding!

  15. Async/Await without Try/Catch Block in JavaScript

    This broke all the conciseness from async/await again, because instead of having asynchronous callbacks in then/catch blocks, we ended up with a try/catch block surrounding everything.

  16. How to use Async Await in JavaScript

    There are many ways JavaScript provides us with the ability to make it behave like an asynchronous language. One of them is with the Async-Await clause.

  17. The 80/20 Guide to Async/Await in Node.js

    The 80/20 Guide to Async/Await in Node.js. Arguably the biggest new feature in Node.js 7.6.0 is that the much awaited async function keyword is now available without a flag. Callback hell and promise hell are now in the past. But, like Uncle Ben always reminded us, with great power comes great responsibility, and async/await gives you a lot of ...

  18. SyntaxError: await is only valid in async functions, async generators

    The JavaScript exception "await is only valid in async functions, async generators and modules" occurs when an await expression is used outside of async functions or modules or other async contexts.

  19. javascript

    To access the response of Promise, you have to use .then() method or await which can return the resulting object of Promise is instead of Promise itself. To change variables from await, you have access and change the variable you want to assign within the async function instead of return from it. //Save response on a variable.

  20. javascript

    I have a hard time understanding how async and await works behind the scenes. I know we have promises which make our non blocking code by using the "then" function we can place all the work we need to do after the promise is resolved. and the work we want to do parallel to promise we just write it outside our then function. Hence the code becomes non blocking. However i don't understand how ...