← JavaScript

Asynchrony

What are `async` and `await`, and what advantage do they have over promises with `.then()`?

Show answer — try answering out loud first

async/await is a syntax for working with promises in a way that looks like synchronous code. await pauses the function until the promise resolves. Errors are handled with try/catch. The advantage is that the code is more readable and easier to follow.

  • async: goes before a function. It makes the function always return a promise.
  • await: is used inside an async function. It waits for a promise to resolve and returns its value, without blocking the main thread.

It's "syntactic sugar" over promises: underneath, there are still promises, but the code reads top to bottom, as if it were synchronous. Errors, which with .then() are caught with .catch(), are handled here with try/catch.

// A function that returns a promise
function obtenerUsuario() {
  return new Promise((resolve) => {
    setTimeout(() => resolve({ nombre: "Mike" }), 500);
  });
}

// With async/await (readable, top to bottom)
async function mostrarUsuario() {
  try {
    console.log("Cargando...");
    const usuario = await obtenerUsuario(); // waits here
    console.log(usuario.nombre); // "Mike"
  } catch (error) {
    console.log("Error:", error);
  }
}
mostrarUsuario();

// Comparison: the same with .then()
function mostrarConThen() {
  console.log("Cargando...");
  obtenerUsuario()
    .then((usuario) => console.log(usuario.nombre))
    .catch((error) => console.log("Error:", error));
}

// An async function always returns a promise
async function saludar() {
  return "Hola";
}
saludar().then((mensaje) => console.log(mensaje)); // "Hola"
  • Using await outside an async function (it throws an error, except at the top level of modern modules).
  • Forgetting the try/catch and leaving errors unhandled.
  • Putting await in a loop sequentially when the tasks could run in parallel. If they're independent, it's better to use await Promise.all([...]).

"async/await is a more readable way to work with promises. I mark the function as async, and with await I wait for a promise to resolve, getting its value directly, without chaining .then(). Underneath they're still promises, so an async function always returns a promise. I handle errors with try/catch. The big advantage is that the code reads top to bottom as if it were synchronous, which is easier to follow than many chained .then() calls."

Quick challenge

In what order does this print?

async function prueba() {
  console.log("1");
  await Promise.resolve();
  console.log("2");
}
console.log("0");
prueba();
console.log("3");
See answer

0, 1, 3, 2. First 0 is printed, then prueba() is called and 1 is printed. When it reaches the await, the function pauses and yields control, so 3 is printed. Finally, what comes after the await (2) runs as a microtask.