DMarlon Studio

Lesson 12 · 12 of 20

async and await · JavaScript

Write asynchronous JavaScript that reads top to bottom with async and await, and handle its errors with try/catch.

JavaScript · async and await in DMarlon Studio: the example's code and its output in the terminal

A function marked `async` always returns a promise, even when it returns a plain value: the first line of output confirms it (Promise). What it returns becomes the promise's value, and what it throws becomes its rejection, as getUser does when the user does not exist.

`await` waits for a promise to settle and hands you its value. In cartSummary the code reads top to bottom as if it were synchronous: first the user, then their cart, then the total. While it waits, only that function is paused; the rest of the program (other timers, events) keeps running.

Errors are handled with the familiar `try`/`catch`: if the promise behind an await is rejected, the error jumps to catch. So user 3 produces Error: user 3 not found without stopping the program, and Luis, whose cart does not exist, shows 0 items thanks to ?? [].

Because CommonJS does not allow await outside a function, the program lives in async function main(), called at the end. In the for...of loop, each await lets one summary finish before the next one starts. In DMarlon Studio's Electron, React, Next.js and React Native targets, this is the style you will see for reading data from an API or a database.

Code · main.js

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));const users = { 1: { name: "Ana", cartId: 10 }, 2: { name: "Luis", cartId: 20 } };const carts = { 10: [{ item: "Book", price: 15 }, { item: "Lamp", price: 32 }] };async function getUser(id) {  await delay(20); // pretend this is a database query  if (!users[id]) throw new Error(`user ${id} not found`);  return users[id];}async function getCart(cartId) {  await delay(20);  return carts[cartId] ?? [];}// await pauses this function (not the whole program) until the promise settles.async function cartSummary(userId) {  try {    const user = await getUser(userId);    const cart = await getCart(user.cartId);    const total = cart.reduce((sum, line) => sum + line.price, 0);    return `${user.name}: ${cart.length} items, ${total} EUR`;  } catch (err) {    return `Error: ${err.message}`; // a rejected await lands in catch  }}async function main() {  const pending = cartSummary(1);  console.log("An async function returns:", pending.constructor.name);  console.log(await pending);  for (const id of [2, 3]) console.log(await cartSummary(id));  console.log("Done");}main();

Output · node main.js

An async function returns: Promise
Ana: 2 items, 47 EUR
Luis: 0 items, 0 EUR
Error: user 3 not found
Done

Key points

  • An async function always returns a promise.
  • await pauses only the current function until the promise settles.
  • A rejection inside await is caught with try/catch.
  • In CommonJS, await goes inside an async function such as main().

Exercise

Add an async getDiscount(user) function that waits 10 ms and returns 10% for Ana and 0% for everyone else, and use it in cartSummary to print the discounted total.