Promises are a very handy tool for organizing asynchronous code. But the human brain is much more accustomed to synchronous operations. We’d much rather prefer to do something, wait, and then continue instead of having to handle inherent complexity of asynchronous programming.

Await

To simplify asynchronous operations, JavaScript came up with the await keyword. If you write it in front of a function that returns a promise, then program execution will stop until the promise is resolved.

const userCount = await getUserCount();

console.log(userCount); // 12345

The screen will immediately display the value with which the promise resolves. In our case, the actual user count that we get from getUserCount(). And if you don’t write await, then we will see the line Promise {<pending>} instead of the user count in the console.

Async

The await keyword can’t be used in a regular function. It is necessary to make it asynchronous by adding the keyword async before the list of function parameters.

const logUserCount = async () => {
  const userCount = await getUserCount();
  console.log(userCount);
}

All asynchronous functions return Promise even if there is no await inside them.

const getHelloWorld = async () => {
  return 'Hello, world!';
}

console.log(getHelloWorld); // Promise {<pending>}

And to get the result of a promise, you need to add the same await keyword. Or remove async, if you are sure that the getHelloWorld function will only perform synchronous operations.

const getHelloWorld = async () => {
  return 'Hello, world!';
}

console.log(await getHelloWorld()); // Hello, world!

Error processing

An error can always occur in the programs you write. Especially in the modern JavaScript asynchronous programming. The file may not be available when we try to read it. Or the Internet may disappear when we load a picture from a remote server.

Errors in promises are handled with .catch():

fetchUserData(userId).then(console.log).catch(handleError);

But if you use await to await a promise, then you can use a regular try/catch block to handle errors:

try {
  await fetchUserData(userId)
} catch (e) {
  console.log('asynchronous error was caught!');
  handleError(e);
}