Async & Await

Here is what we have so far:

console.log("listening for events");
getUser(1)
  .then((user) => getLoans(user["Account number"]))
  .then((loans) => getTransactions(loans["Most recent"]))
  .then((transactions) => {
    console.log(transactions);
  })
  .catch((error) => {
    console.log(error); // probably need to do more than this!
  });
console.log("still listening for events!");

We can make this code even simpler using the new JavaScript feature async/await (which they have borrowed from C#).

Async/Await allows you to write asynchronous code that looks like synchronous code!

Anytime you are calling a function that returns a Promise, you can "await" its results, and then get the results just like calling a synchronous function.

For example, instead of

getUser(1)
  .then((user) => console.log(user))

we can write

const user = await getUser(1);
console.log(user);

So, we can rewrite the code at the top of the page as

console.log("listening for events");
try {
  const user = await getUser(1);
  const loans = await getLoans(user["Account number"]);
  const transactions = await getTransactions(loans["Most recent"]);
  console.log(transactions);
} catch (error) {
  console.log(error);
}
console.log("still listening for events!");

There is one caveat however! You cannot use the await operator in any place that you want. The operator await can only be used inside a function, and that function must be decorated with the async modifier. So we must do something like this:

async function displayTransactions() {
  try {
    const user = await getUser(1);
    const loans = await getLoans(user["Account number"]);
    const transactions = await getTransactions(loans["Most recent"]);
    console.log(transactions);
  } catch (error) {
    console.log(error);
  }
}

console.log("listening for events");
displayTransactions();
console.log("still listening for events!");

Async/Await are syntax sugar! Under the hood, it is converted to a chain of Promises!

Putting it all together
function getUser(id) {
  console.log("Reading a user from a database...");
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("Received user data...");
      resolve({ ID: id, "Account number": "58721094531267" });
    }, 2000);
  });
}

function getLoans(account) {
  console.log("Request for loan data...");
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("Received loan data...");
      resolve({ "Most recent": "loan 3", All: ["loan 1", "loan 2", "loan 3"] });
    }, 2000);
  });
}

function getTransactions(loan) {
  console.log("Request for transactions data...");
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("Received transactions data...");
      resolve(["tran 3", "tran 2", "tran 1"]);
    }, 2000);
  });
}

async function displayTransactions() {
  try {
    const user = await getUser(1);
    const loans = await getLoans(user["Account number"]);
    const transactions = await getTransactions(loans["Most recent"]);
    console.log(transactions);
  } catch (error) {
    console.log(error);
  }
}

console.log("listening for events");
displayTransactions();
console.log("still listening for events!");

I recommend watching Fireship's short YouTube video "The Async Await Episode I Promised" to further solidify your understanding of this subject.