The Codex / JavaScript / Async & Promises

Async & Promises

Callbacks, Promises, async/await, and fetch — handling things that take time in JavaScript.

What it is, in plain English: Asynchronous code is code that starts running now but finishes later — fetching data from a server, reading a file, waiting for a timer. JavaScript handles this with Promises: an object that represents a value that isn't ready yet. async/await is the modern syntax that makes Promises look and feel like regular sequential code, while still being non-blocking. Understanding async is the gateway to real-world JavaScript.

Code that waits — and why JavaScript needs it

Imagine you're building a weather app. When the user opens it, you need to fetch the current temperature from a server. That takes time — maybe half a second. If JavaScript stopped everything and waited, the entire page would freeze. Buttons wouldn't work. Nothing would respond. That's not acceptable.

JavaScript's answer: start the fetch, keep doing other things, and when the data arrives, handle it. This is asynchronous programming.

The old way: callbacks

// A callback is a function you pass to another function, to be called "when ready"
setTimeout(function() {
  console.log("This runs after 1 second");
}, 1000);

console.log("This runs immediately");
// Output:
// "This runs immediately"
// "This runs after 1 second"  ← one second later

Callbacks work, but they get messy fast — "callback hell" happens when you need multiple async operations in sequence:

// Callback hell — hard to read, hard to maintain:
getUser(1, function(user) {
  getPosts(user.id, function(posts) {
    getComments(posts[0].id, function(comments) {
      // now we can actually do something...
    });
  });
});

Promises — a cleaner approach

A Promise is an object that represents a value that will be available in the future. It's either pending (not done yet), fulfilled (succeeded), or rejected (failed).

// A function that returns a Promise:
function getWeather(city) {
  return new Promise((resolve, reject) => {
    // Simulate a network request (takes 500ms):
    setTimeout(() => {
      if (city === "Unknown") {
        reject(new Error(`City "${city}" not found`));
      } else {
        resolve({ city, temp: 28, condition: "Sunny" });
      }
    }, 500);
  });
}

// Use .then() to handle success, .catch() for errors:
getWeather("Mumbai")
  .then(data => {
    console.log(`${data.city}: ${data.temp}°C, ${data.condition}`);
  })
  .catch(error => {
    console.error("Error:", error.message);
  });

async/await — Promises made readable

async/await is syntactic sugar over Promises. It lets you write async code that reads like synchronous code — no chains of .then().

// Mark the function as async:
async function showWeather() {
  try {
    // 'await' pauses this function until the Promise resolves:
    const weather = await getWeather("Mumbai");
    console.log(`${weather.city}: ${weather.temp}°C`);

    // You can await multiple things in sequence:
    const weather2 = await getWeather("Delhi");
    console.log(`${weather2.city}: ${weather2.temp}°C`);

  } catch (error) {
    // If any await throws, execution jumps here:
    console.error("Failed:", error.message);
  }
}

showWeather();

// Important: the code AFTER calling an async function runs immediately:
console.log("Getting weather..."); // this prints FIRST
Key insight: await only pauses the function it's in, not the whole program. JavaScript keeps running other code while waiting. That's what makes it non-blocking.

fetch — the most common real-world async operation

// fetch() returns a Promise — use await with it:
async function getUser(id) {
  try {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);

    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`);
    }

    const user = await response.json();  // also a Promise!
    console.log(`Name: ${user.name}`);
    console.log(`Email: ${user.email}`);

  } catch (error) {
    console.error("Request failed:", error.message);
  }
}

getUser(1);

Note: fetch() works in browsers. In Node.js it's built-in from v18+. The Try It editor above runs in the browser, so fetch to external URLs works there.

Running multiple Promises in parallel

async function getMultipleUsers() {
  // Sequential — slow (waits for each before starting next):
  const user1 = await getWeather("Mumbai");
  const user2 = await getWeather("Delhi");   // starts after Mumbai finishes

  // Parallel — fast (all start at the same time):
  const [mumbai, delhi] = await Promise.all([
    getWeather("Mumbai"),
    getWeather("Delhi")
  ]);
  console.log(mumbai.city, delhi.city);  // both arrive together
}
Try It Yourself

Official Sources

The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.