JavaScript Async/Await

Async/await is syntactic sugar built on top of Promises. It allows you to write asynchronous code that looks and behaves like synchronous code, making it easier to read and maintain.

The async Keyword

The async keyword is placed before a function declaration to make it an async function. An async function always returns a promise. If the function returns a value, the promise is resolved with that value.

async Function
async function greet() {
  return 'Hello, World!';
}

// An async function returns a Promise
greet().then(function(message) {
  console.log(message);
});

// Equivalent to:
function greetPromise() {
  return Promise.resolve('Hello, World!');
}

greetPromise().then(function(message) {
  console.log('Promise version: ' + message);
});

The await Keyword

The await keyword can only be used inside an async function. It pauses the execution of the async function until the promise is resolved, and then returns the resolved value.

Using await
function delay(ms) {
  return new Promise(function(resolve) {
    setTimeout(resolve, ms);
  });
}

async function demo() {
  console.log('Starting...');
  await delay(1000);
  console.log('After 1 second');
  await delay(1000);
  console.log('After 2 seconds');
  return 'Done!';
}

demo().then(function(result) {
  console.log(result);
});

Error Handling with try/catch

With async/await, you can use standard try/catch blocks to handle errors, just like synchronous code. This replaces the .catch() method used with promises.

try/catch with async/await
function fetchData(shouldFail) {
  return new Promise(function(resolve, reject) {
    if (shouldFail) {
      reject(new Error('Data fetch failed!'));
    } else {
      resolve({ id: 1, name: 'Product' });
    }
  });
}

async function getData() {
  try {
    const data = await fetchData(false);
    console.log('Success: ' + data.name);

    const bad = await fetchData(true);
    console.log('This will not run');
  } catch (error) {
    console.log('Caught: ' + error.message);
  }
}

getData();

Async Arrow Functions

You can also create async arrow functions. The async keyword comes before the parameter list.

Async Arrow Functions
const fetchUser = async (id) => {
  return { id: id, name: 'User ' + id };
};

const processUser = async (id) => {
  const user = await fetchUser(id);
  console.log('Processing: ' + user.name);
  return user;
};

processUser(42).then(function(user) {
  console.log('Result: ' + JSON.stringify(user));
});

Sequential vs Parallel Execution

By default, multiple await statements run sequentially. To run promises in parallel, use Promise.all() with await. This is important for performance when tasks are independent.

Sequential vs Parallel await
function fetchItem(name, ms) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(name);
    }, ms);
  });
}

// Sequential (slower)
async function sequential() {
  const a = await fetchItem('A', 100);
  const b = await fetchItem('B', 100);
  console.log('Sequential: ' + a + ', ' + b);
}

// Parallel (faster)
async function parallel() {
  const [a, b] = await Promise.all([
    fetchItem('A', 100),
    fetchItem('B', 100)
  ]);
  console.log('Parallel: ' + a + ', ' + b);
}

sequential();
parallel();
FeaturePromisesAsync/Await
Syntax.then()/.catch()await / try-catch
ReadabilityChain-basedLooks synchronous
Error handling.catch()try/catch
DebuggingHarder (async stack)Easier (step through)
Parallel executionPromise.all()await Promise.all()
📝 Note: The await keyword only pauses the execution of the async function it is in, not the entire program. Other code outside the async function continues to run. Top-level await is available in ES modules, allowing you to use await outside of async functions in module contexts.
Exercise:
What does the await keyword do?
Try it YourselfCtrl+Enter to run
Click Run to see the output here.