In this video as promised we'll be taking a quick break from exploring new Mongo DB features to talk
about something called Promises Promises make it easy for us to manage our asynchronous code and they
were designed to solve many of the problems that we run into when using callbacks in our application.
Now you might be wondering why now why learn about callbacks and use them for so long only to replace
them with promises promises actually build on the callback pattern so it's necessary to understand how
callbacks work and how we can use them before we'll be able to understand.
Promises promises are nothing more than an enhancement for callbacks making it a bit easier to manage
our asynchronous code.
The goal of this video is to give us our first exposure to promises to explore what they are and how
they work.
In the following videos we'll actually integrate promises into our Mongo DB code.
For now though I'm actually going to close this file down and we're going to move over to the playground
directory in here.
We're going to create a brand new file eight hyphen promises Don J S and in here we're going to work
with a promise example.
Now to really understand how promises work it's best to compare and contrast them with each additional
callback pattern.
Now I have this file for height and callbacks from earlier in the class.
If you don't have that or you don't have any content inside of there that's OK.
I'm actually gonna be emptying this file out too and starting with a basic callback example.
Then we'll see how we can do the exact same thing using promises so allow us to view these files side
by side.
What I'm gonna do is double click this little file icon to close down the tree view.
Then I'm going to split the editors.
Side by side I'll have callbacks over here on the left and I'll have the premises file over here on
the right.
And we're going to spend the whole video just working with these two files.
Let's get started with the callback example.
Then we'll convert it over to promises.
What I'm gonna do is create a new function something like do work callback and we'll create do work
promise over in the promises file shortly.
Now this is going to be a function that performs some sort of made up asynchronous task.
We're going to simulate a delay using set time out and we'll do the same thing with promises just to
explore the basic syntax.
But don't worry we will learn how to use promises in the real world.
Shortly we'll be using them for everything including connecting to mongo D.B. to read write update and
delete our data.
For now though we have do work call back and we can go ahead and call that do work callback and the
whole point of using the callback pattern as a way to allow the caller of due work callback to get the
results.
So I provide a callback function and this function runs when I have either the error or the result.
So right here the first argument is for the error and the second argument is for the result.
We've seen this pattern with all of our callback functions including those from mongo D.B..
So from here we can go ahead and do things with the error or the result before we do though.
Let's start filling out do work callback.
We know we're getting an argument passed in when the function is called.
So up here I will name that parameter and it's typically called callback.
Though I could call it whatever I'd like and down below we'll start the process of simulating that asynchronous
process.
So right here we'll be using set time out to get that done.
We provide the function to run after the set amount of time and the amount of time we'd like to wait.
I'll wait.
Two thousand milliseconds which is just two seconds now from here the asynchronous task is complete
and we can signal to the caller that we either got an error or we got a result we got the correct success
data right here.
We do that by calling callback with one of two arguments if things went poorly.
We provide just the first argument and in this case I could have a string like this is my error.
The second argument would be undefined.
We could set it to undefined by not providing it at all or by explicitly setting it to undefined like
we're seeing here.
Either way would work now with the callback pattern.
We have to put a little bit of conditional logic in here because this is the only function that runs
it runs for both failures and for successes.
That means we use patterns like what we've seen plenty of times in the course.
If there is an error we want to run some special code I'll be using return to stop the function execution
and I'll go ahead and use console dot log to dump the error to the terminal.
If there is no error then we must have gotten a result and down below we could go ahead and dump that
to the terminal as well.
So right here we have a very basic example of the callback pattern and we can go ahead and run this
program before continuing on in the terminal down below.
I'll use C D.
Dot dot forward slash playground to navigate over to that playground directory and from here we'll run
our file node for callbacks dot J S when we run it.
What are we going to see.
Well after that two second delay I would expect to see my error message and that is exactly what I get
right here.
Now if things went well we could signify that by calling callback with a different set of arguments
instead of providing the first.
We would just provide the second.
So right here I can do something like Call callback providing undefined which would be the error value.
And then for the second argument providing those success results let's say in this case we're getting
an array of numbers back.
I'll use 1 4 and 7.
Now if I was to save the program and rerun things we should see our numbers printing after two seconds
and down below.
That's exactly what we're getting because result had a value down here the error code didn't run and
we got our result printing.
So this is the callback pattern we've seen plenty of times before.
I wanted to work through it one more time just so we had a side by side comparison between how these
two different setups work.
So with callbacks we can see that the order we call the callback is important.
The first one being the error and the second being the result.
And we can also see that down below we add a little bit of conditional logic to figure out if things
went well or if they went poorly.
Now let's go ahead and do the same thing.
But using the new promises API for the promises example we'll be starting off much the same way.
I'm going to create a new constant called do work promise and I'll set this equal to a new promise.
Now to create a promise.
We use the new operator with the promise constructor function.
So we call it like this.
Now most of the time we as know developers we're not going to be the ones creating promises.
Typically they'll be created by the libraries we use as an example when we use promises with Mongo D.B..
We're not actually going to create new promises at all.
All of that happens behind the scenes inside of the library itself.
But to understand how promises work it's essential to at least become familiar with this syntax.
Now when we call new promise we provide it to it just a single argument.
That is a function and we could make this an arrow function and that would work just fine though you
could also use a standard function if you wanted to.
This function gets called by the promise API and we get access to two arguments we have first up resolve.
And second we have reject and we'll end up using both of these as we move through the process of completing
our asynchronous task.
Now for us that task is still going to be just simulating a delay using set time out.
So let's go ahead and get to it right here.
Set time out passing in our function and the amount of time we'd like to wait.
Once again I'll just wait two seconds.
Now when it's done we are ready to signify that we've completed the asynchronous process in the past
with the callback pattern we would signify this by calling the callback in one of two ways.
I would provide that first argument if things failed and I would provide the second argument if things
succeeded in our case.
What we have are two separate functions.
I have resolve and reject if things went well and we got the result we were expecting we call resolve.
If things went poorly and we did not get the result we were expecting we would call reject.
So right here we're gonna see some clearer semantics when working with promises it can be a bit difficult
to easily figure out that this means success and this means failure because the order of arguments plays
an important role over here.
The name of the functions clearly signifies that.
So what I'm going to do is use resolve to say that things went well.
Now we can pass to resolve and to reject a single value so as an example if I was calling reject I would
pass in my error if I was calling resolve I would pass in my success information.
In this case since I am calling resolve I'll pass in another array of numbers to signify that we've
got the results we were expecting right here 7 4 and 1.
Perfect.
So at this point we actually have the promise created it's going to wait those 2 seconds then it's going
to signify that things went well.
The question is what's the other half what we have here is essentially equivalent to what we have here.
How exactly though do we do something when the asynchronous process is complete down below.
We do that by using various methods on do work promise.
Now in this example do work promise is the actual promise and a promise is nothing more than an object
with a few methods that we can access down below.
Let's go ahead and explore them do work.
Promise DOT and the first method we're gonna use is dot then dot then allows us to register a function
to run when things go well so when resolved is called right here we can set up that function and we
get access to the data.
The promise was resolved with.
This first and only parameter.
So right here I can call that result and result lines up with what we had over here called the result.
So this function only gets executed when things go well.
Right here I'm going to use console dot log to print two things.
First up I will print success then as the second argument to console dot log I'll dump the result variable
to the screen.
Let's go ahead and run the program and see what we get down below.
That's gonna be node 8 hyphen promises dot J S and when I execute it we still wait those two seconds
since promises help us maintain and manage our asynchronous code.
Then after those two seconds are up we got success and we got our data.
Now things don't always go well.
If we're using promises to query the database maybe the network connection drops and we can't access
the database server.
In that case we wouldn't call resolve.
Instead we would go ahead and call reject now reject is similar to resolve in the fact that it accepts
just a single optional argument.
And in this case that would be the error.
So that would be similar to what we would pass as the first argument to our callback function in the
callback example right here.
I'll go ahead and do just that.
I'll print the message.
Things went wrong.
Perfect.
Now when we call reject this function is not going to run.
Remember this only runs if things go well.
Right here we can chain on a another method call to the catch method.
And this allows us to register a function to run when reject is called.
So right here what I'm gonna do is pass in that function we're going to get access to the error and
then we can go ahead and use it.
So right here I'm just going to dump it console dot log.
First up I will print error.
Then I'll actually dump the variable value to the terminal.
Now with this in place let's go ahead and run the example once again from the terminal.
We're gonna wait our 2 seconds and when the two seconds are up we get things went wrong.
Printing to the terminal.
Now right away there are some clear advantages to working with promises one is clearer semantics it's
easier to understand the intention of the code.
So over here we have resolve and reject.
We have two separate functions we call and that makes it easier to just pass this code and figure out
what's going on.
If resolve is called We know things went well and this is our data.
If reject was called we know that things went poorly and this is the error with the callback pattern.
We just have these single function which means we need to look at all calls to callback and then figure
out which of the two arguments was provided.
Which is more error prone and easier to run into issues with the next benefit has to do with the setup
we have for doing something when an asynchronous task is complete with a callback pattern.
We have just a single function.
It's up to us the developers to determine whether or not an error occurred and run the correct code.
We did that using the if statement up above.
When we're working with promises we have two separate functions.
Only one of which will ever run down below.
For example when reject was called we got our error printing which means that this function did indeed
run it but we never got success printing.
Which means that this function never ran.
So with promises it's not up to us to add that conditional logic into place.
We provide two separate functions making it easier for us to manage our asynchronous tasks.
One more advantage of working with promises is that it makes it easy to not mess up and what I mean
by that has to do with this function right here in this function.
We can call either resolve or reject.
We can't call both and we can't call one of them twice.
I can't reject two times once either resolve or reject is called.
The promise is done and its value or state can't change so we can't change the error message by calling
reject again and I couldn't bring it from a failure to a success by calling resolve.
Down below there's nothing built into the callback pattern to prevent that.
So over here there's nothing to stop me from running this code and calling callback twice.
Now this doesn't make any sense at all because our asynchronous operation should have either worked
or not worked.
It shouldn't have had both occur with promises.
We don't have to worry about that and let's go ahead and quickly prove it down below what I'm gonna
do is try to call resolve.
I'm going to call resolve and I'm going to pass in some data to 3 and 2.
This call is not going to cause the program to crash but it's going to have no effect on how the program
runs at this point.
When reject is called the premise stops looking for new calls to resolve or reject.
Down below I'll go ahead and run the program.
We wait our two seconds and we get our error message.
At no point do we see the success message with this data.
Now the same is true with trying to call the same method again.
So for example I can't call reject providing a new error.
That's not gonna work either.
If I do go ahead and run the program for a final time we're going to see that we only get the first
error showing up.
So with promises there are rules enforced behind the scenes that makes it a bit easier to not mess up
so it makes it easier to get the desired behavior that we're looking for and it makes it easier to squash
those pesky asynchronous bugs.
Now let's wrap up the video by talking about one of my favorite things with any new programming feature
vocabulary.
So as we're using promises we want to be able to discuss what's happening using terms that make sense
for all of us.
Now we're only going to introduce three new terms.
Down below I have a series of JavaScript comments that create a little visualization.
So right here we have a promise.
When we first create the promise the promise is known as pending.
So our promise is pending for the two seconds before resolve or reject is called a promise is pending
until either resolve or reject is executed.
Now if resolve is called your promise is considered the filled if reject is called your promise is considered
rejected.
So in our case I could say that I have a promise called do work promise.
It's pending for two seconds and then it's rejected.
If I were to flip the switch on these comments and call resolve and comment out reject I would say I
have a do work promise.
It's pending for two seconds then the promise is fulfilled.
So it's important to just be familiar with these three terms as they're going to come up as we discuss
promises.
Now this is just the beginning with our work on promises.
You're probably wondering what does this all look like in a real situation.
Well it's actually pretty similar to what we see right here in the next video.
You're going to learn how to use promises with Mongo D.B. since Mongo D.B. has built in support for
them.
We're gonna talk about updating our documents and we'll do so using promises.
Now I have more to say about other promise features but we'll discuss those throughout the course as
they become necessary.
I'm excited to continue on.
Let's go ahead and jump right in to the next video.