All posts
JavaScriptSeptember 10, 20268 min read

JavaScript Async/Await for Beginners: A Simple Guide

Learn JavaScript async/await for beginners with plain-English explanations and small code examples you can copy, run, and understand line by line.

F
Fepiq Team
Fepiq

If you searched for "JavaScript async/await explained for beginners," here is the short answer: async/await is a way to write code that waits for slow things (like loading data from the internet) without making your code confusing. It lets you write "wait for this, then do that" logic in a style that reads top to bottom, just like normal code.

In this guide, we will build up to async/await one small idea at a time. You do not need any prior experience with promises or asynchronous code. Every term is explained the first time it appears, and every code example is short enough to copy, paste, and run yourself.

What does "asynchronous" mean?

Most of the code you write runs synchronously, meaning line by line, in order, and each line waits for the one before it to finish. But some tasks take an unknown amount of time, such as fetching data from a server, reading a file, or waiting a few seconds before doing something. These are called asynchronous tasks.

JavaScript does not want to freeze your whole program while it waits for a slow task. So it lets that slow task run in the background and continues running other code in the meantime. Async/await is the modern way to say "pause here, in this specific spot, until the slow task finishes" without freezing anything else.

A quick primer on promises

To understand await, you first need to know what a promise is, because await only works with promises. A promise is an object that represents a value you will get later, not right now. Think of it like a food delivery tracking number: you do not have your food yet, but you have something that will eventually tell you it arrived (or that something went wrong).

A promise can be in one of three states: pending (still waiting), fulfilled (it succeeded, and you now have a result), or rejected (it failed, and you get an error instead). Functions like fetch(), which loads data from the internet, return a promise immediately, even though the actual data has not arrived yet.

The async keyword

Adding the word async in front of a function turns it into an async function. An async function always returns a promise, even if you write a plain value inside it. JavaScript automatically wraps your returned value in a promise for you.

js
async function greet() {
  return "Hello!";
}

greet().then((message) => console.log(message));
// Output: Hello!

Line by line: `async function greet() { ... }` declares an async function named greet. Inside it, `return "Hello!";` looks like a normal return, but because the function is async, JavaScript actually returns a promise that resolves to the string "Hello!". On the last line, `greet()` runs the function and gives us that promise, and `.then((message) => console.log(message))` says "once the promise is fulfilled, run this code with the result."

The await keyword

The await keyword can only be used inside an async function. It pauses that function on the current line until the promise next to it settles (either fulfilled or rejected), then gives you the result directly, instead of making you write a `.then()` call.

js
function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function sayHiLater() {
  console.log("Waiting...");
  await wait(1000);
  console.log("Hi! (this printed after 1 second)");
}

sayHiLater();

Here is what each part does. `wait(ms)` is a helper function that returns a new promise, which resolves (finishes successfully) after `ms` milliseconds, using JavaScript's built-in `setTimeout`. Inside `sayHiLater()`, we log "Waiting..." first. Then `await wait(1000)` pauses the function for one second (1000 milliseconds) before moving to the next line. Finally, we log the second message. Notice that the code reads top to bottom, even though it includes a real delay — that is the whole point of async/await.

A real example: fetching data from an API

The most common place you will see async/await is when loading data from a server using the built-in `fetch()` function. Fetch returns a promise, so it pairs naturally with await.

js
async function getUser() {
  const response = await fetch("https://api.github.com/users/octocat");
  const data = await response.json();
  console.log(data.name);
}

getUser();

`fetch("https://api.github.com/users/octocat")` starts a request to a web address and returns a promise, so we `await` it to get the actual response once it arrives. That response contains raw data, so `response.json()` converts it into a usable JavaScript object — this is also asynchronous, so we `await` it too. Once both steps finish, `data` holds the real information, and we can read `data.name` like any normal object property.

Handling errors with try/catch

When a promise is rejected (something went wrong, such as no internet connection), an `await` on that promise throws an error. You can catch that error using a try/catch block, the same way you would catch errors in regular JavaScript code.

js
async function getUserSafely() {
  try {
    const response = await fetch("https://api.github.com/users/octocat");
    const data = await response.json();
    console.log(data.name);
  } catch (error) {
    console.log("Something went wrong:", error.message);
  }
}

getUserSafely();

The `try` block wraps the code that might fail. If any `await` inside it throws an error, JavaScript immediately jumps to the `catch (error)` block instead of crashing your program, and `error.message` gives you a readable description of what went wrong. This is the standard, recommended way to handle errors with async/await.

async/await vs. .then(): what's the difference?

Async/await does not replace promises — it is just an easier way to write code that uses them. Under the hood, both approaches do the same thing. Here is a side-by-side comparison of the two styles:

TaskWith .then()With async/await
Wait for one resultfetch(url).then(res => res.json())const data = await fetch(url)
Wait for several steps in orderChained .then() calls, nested deeper each timeMultiple await lines, one after another
Handle errors.catch(error => ...)try { ... } catch (error) { ... }
Readability for beginnersCan get hard to follow with many stepsReads like normal, top-to-bottom code

Not confident with functions yet? Async functions are still just functions, with one extra keyword.

Read our JavaScript Functions guide

Common mistakes beginners make

  • Forgetting to add async before a function that uses await — this causes a syntax error.
  • Forgetting to write await in front of a function call that returns a promise, so you get a Promise object printed instead of the actual value.
  • Thinking async/await makes code run faster — it does not. It only makes waiting code easier to read and write.
  • Wrapping the entire function body in one giant try/catch when you only need to catch errors around the risky part.
  • Trying to use await inside a regular function that is not marked async.

Practice: put it together

Try writing your own async function that fetches a joke from a public API and prints it to the console. Start with the getUser() example above, change the URL, and change data.name to whatever property the new API returns. Making small changes to working code like this is one of the fastest ways to build confidence with async/await.

Frequently asked questions

What is the difference between async/await and promises?+

They are not competing tools — async/await is built on top of promises. A promise is the underlying object that represents a future value, while async/await is simply a cleaner syntax for working with that promise, so you can avoid writing long chains of .then() calls.

Can I use await outside an async function?+

No, not in regular JavaScript function bodies — await only works inside a function marked with async. Modern JavaScript modules do allow "top-level await" in some environments, but as a beginner, it is safest to always wrap await inside an async function.

Does async/await make my code run faster?+

No. Async/await does not speed up slow tasks like network requests; it only changes how you write and read the waiting code. The actual task, such as loading data from a server, still takes the same amount of time either way.

What happens if I forget the await keyword?+

If you call a function that returns a promise but forget await, your variable will hold the Promise object itself instead of the actual result. You will often see this by accident when console.log prints something like "Promise { <pending> }" instead of the value you expected.

Is async/await only used with fetch()?+

No, fetch() is just the most common beginner example. You can use await with any function that returns a promise, including timers, file reads in Node.js, and database queries — the pattern is always the same.

Want a developer to build the real thing for you, no code required on your end?

Talk to Fepiq

Get new posts in your inbox

Occasional, no-fluff notes on shipping modern software — startups, automation, Laravel, Shopify and more. No spam, unsubscribe anytime.

Keep reading

Related posts

All posts

Let's build something

Ready to ship your next product with Fepiq?

Book a free discovery call. We'll listen, ask sharp questions, and send you a proposal within 3 business days.