As mentioned in the last video there's one more topic I want to cover.
Related to asynchronous programming before we get back to adding new API roots to the task manager app
and that is async await.
Now I've been working with JavaScript for over a decade and I remember when all of the features I now
take for granted.
First came out things like promises aero functions and others were super exciting and definitely changed
how I wrote code.
In my opinion out of all of those new features we've gotten in JavaScript over the years none is a bigger
improvement to the language than async await async await makes it so easy to work with our asynchronous
promise based code writing code that looks more synchronous than asynchronous.
Now the good news is that async await is not a whole new thing.
It's not like we're going from callbacks to promises to async await async await is merely a small set
of tools that makes it easy to work with promises.
So we're still going to be using the same old promise methods we've used before.
Nothing's gonna change there.
The only thing that's going to change is how we manage our code when we have a lot of asynchronous things
going on.
A single wait is going to play a major role in the task manager application.
We'll be using it in every single root handler.
So I want to take time and make sure we understand what's going on before we focus on integrating it
into existing code.
So to start once again with a new syntax we're going to create a new file in that playground directory
in the node course folder.
I'm reserving this other playground folder in the task manager directory for playground type files that
require a database connection like this one here but to kick things off we're gonna start without worrying
about connecting to a database.
We'll start with simple dummy asynchronous tasks.
Let's go ahead and get started by closing all open editors and we're going to switch over to that playground
directory and we're going to add one more file to the list that's going to be number nine which I can
call a sink python a weight which is the name of the feature we'll be exploring and then down below
in the terminal.
I'm gonna shut things down and navigate over to that directory as well like we've done plenty of times
before.
Now let's go ahead and get started with async a wait and see what it can do for us to get started.
We're going to create the simplest function possible.
I'm going to create a constant do work and we're going to set up the value as an arrow function.
Now for this arrow function for the moment we're not going to accept any parameters and we're not even
going to do anything.
We're gonna have an empty function body down below.
We're gonna go ahead and call this function printing its return value to the terminal.
Right here we'll use console dot log to print something.
What do I want to print.
I want to print whatever comes back from calling do work.
So I'm taking that return value and passing it to console log.
Now what do we know about JavaScript functions.
We know that if we don't explicitly return something from the function undefined is implicitly returned.
So if I was to run the program I would expect to see undefined printing.
Let's go ahead and do just that.
I'm gonna save the script down below.
I'm going to run it node 9 async await dot J S.
Now when I do so we're gonna get exactly what we expected.
I have undefined printing.
Now the reason I'm doing this is because what we're about to do is use async await the first part of
the feature is a sync.
This allows us to create an async function.
And in that function we can use the await feature.
Now this will all make sense once we have a more complete example to start.
Essentially what we need to do is mark a function as an async function.
And this is done by adding the async keyword right before the function declaration.
So right here I have the same old function I had just moments ago.
The only thing I've done is I've added a sink right up front.
Now with this simple change we're actually also changing the behavior of our program.
We're no longer going to get undefined printing in the terminal.
Let's go ahead and rerun the script and see what we get.
I'm going to rerun the script and what do I get.
I no longer get undefined like I was getting before.
Instead what I can see is that do work is returning a promise and that promise has been fulfilled with
the value undefined.
So this is the first important thing to note about async functions async functions always return a promise
that promise is fulfilled with the value you the developer choose to return from the function let's
go ahead and clarify that.
Right now we're seeing the promise get fulfilled with undefined because that's what we're returning
by not explicitly returning anything undefined is implicitly returned.
Let's go ahead and explicitly return something.
I'm going to return a string with my name Andrew.
Now we're going to save this script and we're going to rerun things once again.
Now we have changed the return value but I mentioned that async functions always return a promise.
So the return value of do work is not a string.
It's not this string right here.
Instead it's a promise that gets fulfilled with this string.
So down below we rerun the script from the terminal.
And that's exactly what I see.
If you return value from do work is a promise that has been fulfilled with the string.
Andrew.
Now since we are getting a promise back from due work we can actually use then and catch our promised
methods instead of just taking the promise and dumping it to the console.
So I'm going to remove this console dot log statement and replace it with a call to do work exactly
like we had before.
Then I'll set up a then call to run some code when the promise is fulfilled.
And right here I'll get access to the results.
Now in this case the result is whatever value is returned from do work.
So right here console dot log printing inside of quotes.
The string result followed by the result variable.
So I'm printing it twice once as a label for what I'm seeing.
And then once as the actual value.
And we can also set up a catch call.
So down below a call to catch we're going to set up a function that gets an error.
And right here we'll do the same thing.
Let's go ahead and use the correct syntax for the Arrow function though.
Perfect.
And now we'll use console dot log.
I'll print these string e followed by the actual error.
Now if we run this program since the promise does indeed fulfill with this value I would expect to see
this code run and I would expect to get my result I'm going to save this script rerun things from the
terminal down below.
And that's exactly what we get.
Now how do we ever get catch to run.
Well if we throw an error from our async function that's going to be the same as rejecting the promise
that comes back from the async function.
So when I return a value we're fulfilling that promise with the value we just saw that right here when
I throw an error we're rejecting the promise with that error.
So throw new error and we can pick whatever message we like.
Something went wrong.
Perfect.
Now that we have our throw statement in place let's go ahead and actually run the program one more time
from the terminal down below.
I would expect that my catch function runs and that is exactly what happens if I scroll up I can see
I got my little E string which comes from right here.
Then I have the entire error object printing out down below.
So there we go.
This is the basic structure of an asynchronous function.
The question is why is this useful.
What's the other half to the feature that actually allows us to manage our asynchronous tasks with ease.
This brings us to the other half of async await which is the await operator.
Now the await operator can only be used in async functions.
And now that we have an async function in place we're ready to talk about a wait.
Remember the whole point of async await is to make it easier to work with asynchronous promise based
code.
So let's bring one of our dummy promise functions into the mix.
We don't have to recreate it from scratch.
Let's go ahead and just copy it from our previous playground script.
Right here we have a function that adds up to numbers after two seconds.
I'm gonna take that function in its entirety and I'm going to copy it over to our async await playground
file without changing a single thing about it.
And this is done intentionally when working with async await.
You don't have to change how your promises function internally.
All you do is change how you work with them.
For us that means that Mongoose doesn't need to rewrite the library in order for us to use async await
Mongoose supports promises.
So as a consumer of those promises we can use async await if we wanted to down below.
Let's see how a weight is actually going to help us.
So inside of due work we're going to work with ad calling it a few different times.
Now if we weren't using async await.
I know exactly how I could call add a couple of times adding up some numbers because we did that a few
videos ago in that promise this file we have that down below.
I call ad adding on my first then method I provide the callback where I return the another promise right
here.
Adding up more numbers and I get that result down below.
That's not what it's going to look like with async await we're going to remove the need for all of those
callback functions.
So what we get access to in a sync is the await operator V a wait operator gets used with a promise
we can get a promise because ad returns a promise.
So right here I'm going to call ad to use a wait with a promise and I'll go ahead and add up a couple
of numbers.
I'm gonna add up the number one with the number ninety nine.
Now the sum is one hundred but the question is where do I get access to that data.
If I wasn't using a sink and a weight I would add on a then method call provide my callback function
and I'd get access to the data inside of there with async and a.
It looks as if ad is a standard synchronous function we actually can create a variable right here to
get access to the value that the promise is fulfilled with.
So in this case yes we still have to wait those two seconds.
The advantage is syntactical right here.
It's a lot easier to reason about and pass this code than it is the code we have in the other file.
Now from here I can go ahead and return that sum which is exactly what I'm going to do.
Then we'll go ahead and run the program down below.
I'm going to clear the terminal output just to clean things up a little bit and I'll rerun the script
by using the up arrow twice and enter and when I do so I wait my two seconds I get my result one hundred
back so we can see right here that we're able to use code that looks synchronous to perform asynchronous
tasks.
Now we're only doing a single asynchronous thing right here so it might be hard to see the advantage.
Let's go ahead and switch this function up a little bit.
I'm going to remove the return to some and we're going to add up more numbers so I'm going to create
const some 2 right here.
I'll get the value from using a wait with a another call to add I'll add up that first sum one hundred
with the number 50 and this would be 150 then I could create some 3 going through that process once
again adding up some 2 which is 150 with the number three which would bring me to a total of 150 3.
So now I have some 3 and I could go ahead and return that returning some 3.
Now in this case we are doing 3 asynchronous things and they all take 2 seconds.
So when I rerun the program we still have to wait those six seconds using async and await.
Does it make things fast it just makes things easier to work with.
Right here I get one fifty three printing.
So we wait two seconds to get one hundred.
Then we wait on the next line to get the 150 value and then finally we wait for one fifty three.
So here all of our code runs in order.
Even though asynchronous things are indeed happening behind the scenes now in this case we have code
right here that is much simpler than the promised chaining code.
We had over here promise chaining.
Well useful can cause problems and it's a bit easy to misunderstand what's going on.
We have a lot of different functions and return values.
And when we return something that impacts what happens further down the chain.
This can get us into some confusing situations async await was added to help fight that off.
Right here.
It's pretty easy to see what's going on.
Once you understand what a sink and a weight actually do.
Another big problem with promise chaining is that it's difficult to have all of the values in the same
scope.
So what do I mean by that.
Well right here we have our first some then down below in this function we have access to the second
some.
What if I wanted to have access to both of those sums at the same time to do something like save them
to a database or send them to the user.
There's no easy way to do that but we would have to do is create variables in the parent scope and then
reassign them in here.
And it turns into a mess really quickly with async await.
There's no need to worry about any of that.
I have access to all of the individual results in the exact same scope my async function allowing for
a lot of flexibility.
The last thing we need to discuss before we can actually use async await in the real world is what happens
if one of these promises rejects instead of officials.
Now our ad call up above always calls resolve.
Let's go ahead and switch it up to call reject.
Sometimes we're gonna say that we can only add up positive numbers if either of your numbers are negative
we'll call reject instead.
So right here if we're gonna see if a is less than zero then we'll use the logical or operator to see
if B is less than zero.
So if either of them is less than zero whether it's just one or whether it's both.
This code is going to run I'm going to use return to stop the function execution.
So resolve doesn't get called and I'm going to use reject to provide the error.
I'll say something like numbers must be non negative.
Perfect.
So now we have a call to reject in place.
Now the program in its current state is going to work exactly as it did before and to prove that I'll
rerun it.
We wait our 6 seconds all of the numbers are positive so we get our result printing from this line right
here.
Now let's go ahead and make one of these numbers negative.
What I'm gonna do is make our last call to add provide minus three instead of plus three.
Now what's gonna happen.
Well things aren't gonna crash right away because remember when using async await things happen one
at a time so we wait our two seconds here and everything's fine.
Then we wait our two seconds here and everything's good and then we wait our two seconds here and we
get that error.
So after six seconds we're going to see that a problem occurred.
I'll rerun the program down below to prove that's exactly what happens.
So we're waiting the same amount of time we were waiting before because the error occurs at the very
end.
And then I get my error message printing.
Now if that happened earlier on like in our first call to add we would see the error sooner if this
promise rejects then none of the code down below is going to run it's going to skip right to the catch.
Call down here.
That's why we're seeing EA show up from line twenty three in our program.
So right here with minus ninety nine in the first ad call.
I'll go ahead and rerun things.
Now we still have to wait.
Those initial two seconds then we get the error message in place.
There's no need to even run the other code because something went wrong before that code had a chance
to run.
That's where we're going to stop for this one.
Now I know we spent a lot of time exploring the basic syntax but async await is going to play such a
critical role in our task manager application.
So I want to make sure it got the time it deserved in the next video we'll start to integrate this with
our Mongoose method calls.
I'm excited to get to that.
So let's go ahead and jump right in and once again there will be a challenge where you're going to have
to use async await on your own.