At this point, we have only used half of the feature. We've used the async part, which alone is not particularly useful. It gets really useful when we combine it with await, so let's go ahead and start taking a look at that.
The await function is going to allow us to introduce the other functions back into play, getGrades and getUser. We're just going to go ahead and use await, and then we'll talk about exactly what's happening. So, for the moment, bear with me and just type out this line: const user = and we're going to set it equal to the await keyword. We'll talk about this in just a second; we're going to call getUser and we're going to pass in the userId. So let's start breaking this line down:
const getStatusAlt = async (userId) => {
const user = await getUser(userId);
};
We've done this before; we're calling getUser with the userId. It returns a promise. We're creating a new variable user and it's a constant; it's the await part that's new. So the await keyword, as I mentioned earlier, has to be used in an async function. We're meeting that criteria. We have an async function, which means we can use await inside it.
We use await just before a promise, so here we get a promise back. So, we're awaiting for that promise to either resolve or reject. If that promise resolves, the result of this expression is going to be the resolved value, which means that resolved value will get stored in the user variable. If the promise rejects, it is going to be equivalent to throwing an error, which means no user variable will ever be created. The function will stop executing and we'll get that error inside catch.
Let's go ahead and actually play around with this. What I'm going to do is pass an id into getStatusAlt. Let's go ahead and use Jessica; all we're going to do is console.log(user) to the screen. We want to see what user equals. Now, nodemon is going to restart in the background and my nodemon got cleared before:

Right here, we have our object with an id of 2, the name of Jessica, and the school id of 999.
Now, without await, we would be getting a promise back; with await, we're able to actually get that value back, which is equivalent to what we did previously. It's equivalent to this stuff where we got access to the user and we did something with it but, using async/await, we're able to do this in a way that looks very synchronous.
Now, we can apply this exact same technique to getting the grades. Next to the user const, we're going to make a const called grades. We want those grades back. What we don't want to do is create stupid temporary variables, add complex chaining, and nesting. We just want to get the grades, so we're going to await the following promise, to either resolve or reject. For the one that comes back from getGrades, we pass in a valid school id, user.schoolId:
const getStatusAlt = async (userId) => {
const user = await getUser(userId);
const grades = await getGrades(user.schoolId);
console.log(user, grades);
};
This is going to return the grades array, for that user will be able to dump them to the screen.
So, in the Terminal, we are getting the object and the grades for Jessica:

She just has one grade, so we have an array with a single object inside it. We're not getting back a promise; we're getting back a regular old array. The same thing is true for Andrew; he's going to have those two grades:
getStatusAlt(123).then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});
They're all going to come back and, if I switch this up to an id that's not valid, we're going to get our error: Unable to find user with an id of 123:

That is because the await function rejects, which is equivalent to throwing an error. We saw that when we throw an error from an async function with access to it via catch. So, at this point, we have our user, we have our grades, and we're ready to move on to the final step, which is the actual important stuff. So far, we're just getting data out, took a few lines of code that required us to nest things. At this point, we can take the code snippet for average, exactly as it sits:
let average = 0;
if (grades.length > 0) {
average = grades.map((grade) => grade.grade).reduce((a, b) => a + b) / grades.length;
}
return `${user.name} has a ${average}% in the class.`;
This code relies on a user variable, which we have, and a grades variable, again, we have it as well. We can take it and copy it in the async function like this:
const getStatusAlt = async (userId) => {
const user = await getUser(userId);
const grades = await getGrades(user.schoolId);
let average = 0;
if (grades.length > 0) {
average = grades.map((grade) => grade.grade).reduce((a, b) => a + b) / grades.length;
}
return `${user.name} has a ${average}% in the class.`;
};
Now, we set up our average variable. We calculate the average if there are grades and we return our status:
getStatusAlt(2).then((status) => {
console.log(status);
}).catch((e) => {
console.log(e);
});
At this point, we can use the status and we can print it using the console.log statement. Let's change this back to a valid id, either 1 or 2, some id that does exist. This time, when JavaScript runs through getStatusAlt, it is actually going to return the correct status: Andrew has an 83 in the class or Jessica has a 100 in the class:

We were able to do all of this without a single callback, no chaining, no nesting, just regular old code that looks like synchronous code.
This code is way more readable, maintainable, and understandable than what we have up above. Using async/await, we're going to be able to do just that. We're going to be able to write better, more concise promise-based code. Now, you'll notice that I'm not using await on the functions up above. There is no need to, because we don't need async inside them. One more important thing to note, there is no top-level await. You have to use await inside an async function so, in our case, all that means is that we do use a little chaining at the end, but when we are working with complex chains, we are able to use async/await to get the job done.
At this point, I don't expect you to be able to use async/await on your own. We're going to run through another example using real APIs that's going to give us a little more real-world experience. I'm excited to get to it.