CTCaliberTek
Course: JavaScript Developer Path · Lesson 4 of 4Log in to track your progress and earn a certificate when you finish the course.
Programming

Asynchronous JavaScript: Promises and async/await

Published October 9, 2026·Updated October 29, 2026·9 min read
Like SaveLog in to like, save, and track progress.

Introduction

Many things in JavaScript take time: network requests, timers, reading files. Instead of blocking the program, JavaScript uses promises to represent a result that will arrive later. This tutorial covers promises, the async/await syntax that makes them easier to read, and running tasks in parallel.

Prerequisites

  • JavaScript functions and arrow functions
  • Basic understanding of callbacks

Step-by-Step Guide

Step 1: Understand and create a promise

A promise is in one of three states: pending, fulfilled, or rejected. Wrap a callback-based API in a promise by calling resolve when the work completes.

const wait = (ms) =>
  new Promise((resolve) => setTimeout(resolve, ms));

wait(1000).then(() => console.log("One second passed"));

Step 2: Chain then and catch

then handles a successful result and catch handles any error in the chain. fetch returns a promise for an HTTP response.

fetch("https://api.example.com/users/1")
  .then((response) => response.json())
  .then((user) => console.log(user.name))
  .catch((error) => console.error(error));

Step 3: Write it with async/await

An async function always returns a promise. Inside it, await pauses until a promise settles, so asynchronous code reads top to bottom like synchronous code.

async function loadUser(id) {
  const response = await fetch("https://api.example.com/users/" + id);
  const user = await response.json();
  return user;
}

Step 4: Handle errors with try/catch

fetch only rejects on network failures, not on HTTP error statuses like 404. Check response.ok yourself and throw if it's false.

async function loadUserSafely(id) {
  try {
    const response = await fetch("https://api.example.com/users/" + id);
    if (!response.ok) {
      throw new Error("Request failed: " + response.status);
    }
    return await response.json();
  } catch (error) {
    console.error("Could not load user:", error.message);
  }
}

Step 5: Run independent tasks in parallel

Promise.all starts several promises at once and waits for all of them, which is faster than awaiting them one after another. This example runs inside an async function.

const [user, posts] = await Promise.all([
  fetch("/api/user").then((r) => r.json()),
  fetch("/api/posts").then((r) => r.json()),
]);

FAQs

Why doesn't fetch throw an error on a 404?
fetch only rejects when the request itself fails, such as a network error. HTTP error statuses still resolve, so you need to check response.ok or response.status.
Is async/await different from promises?
No. async/await is syntax built on top of promises. It makes the same asynchronous code easier to read and to wrap in try/catch.

Summary

Promises represent future results, and async/await makes them readable. Always handle errors, check response.ok when using fetch, and use Promise.all to run independent work in parallel.

Related tutorials

Comments

Log in or create a free account to join the discussion.

  • No comments yet. Be the first to comment.