- Promises are used a lot in modern JavaScript
and typically they call rest services
where the result is going to take
a few seconds to come back.
For example, the fetch function returns a promise object.
It returns the Promise object immediately
and the Promise object is like an empty box.
Eventually, the result will be placed into that box
but not just yet.
So what we'll do in this section
first is to describe how promises work in a web application.
And then what we'll do in the next section
is see how to test that.
For this section and the next section,
it's going to be the same code base.
It's the test and Promises folder in lesson four.
Okay, so here's the basic idea.
When you use promises, you create a promise object
and the promise constructor calls you back immediately.
You basically pass a parameter into the promise
a callback function
and the promise constructor
invokes your callback function immediately.
And your callback function receives two parameters,
resolve parameter and reject parameter.
These two parameters are pointers back into the promise.
The idea is that inside your lambda in red here,
you do some long running task.
It might take a few seconds.
If that succeeds, then you call the resolve function
whatever this points to in the promise object
you basically call the resolve function pointer
to tell the promise I have succeeded and choose the result.
It's probably gonna be 42.
If anything went wrong,
then you call the reject call back on the promise
and you give it some kind of error.
Okay?
So there's my long running task.
If the long running task is successful
we invoke the resolve call back.
If it's unsuccessful, we invoke the reject call back.
So the promise object will know at the end of the day
what the result was or what the error was.
In terms of using the promise object
back in your client code
you'd say, having created the promise object
you can say, when that has finished
if it finished successfully by a resolution
then this is the code that I want to execute.
Okay?
So when the promise object is resolved
it'll call you back
it'll call this lambda
it'll pass the result that was returned
and you can do something with it.
On the other hand, if the promise object rejected
then it'll call your catch callback.
And then here you can have some error handling
you'll receive the error parameter,
and you can do something with it,
like display a popup message on the console.
There's also an alternative syntax.
Instead of having a promise dot then do this
dot catch, do that
You can write it slightly differently.
There's a then function on promise
where it takes two parameters,
two lambdas effectively.
The first function is what to do
if the promise was resolved successfully.
And the second parameter is what to do
if the promise was rejected.
Okay?
So, semantically the same idea
just a different way of writing the code.
And if you want to
you can actually set up a chain of promises.
So you can say, right, get that promise running
when it's finished, if it works successfully, then do this.
And in here you might have some other long running task.
And when that's finished do this
and each time, the result of the previous step
gets passed in as the result in here.
So take the next result and do some more work
that would give me back the next result,
pass it into here and do some more work
that would generate another result
Pass that into here and do some more work,
oh, by the way if anything failed,
then call a catch handler here.
In case you can set up a whole pipeline of work to do
one after the other as each promise gets resolved,
go onto the next step.
One of the main benefits
of using promises is how easy it is to set up a chain.
It is much easier to set up a chain
of subsequent steps like this
than it would've been using callbacks.
With callbacks you have a nested handler
and the thing gets very deeply nested
instead of being more sequential like it is here.
Okay, so that's the general idea of promises
to understand promises properly, an example.
So in the test and promises folder
I've got a webpage, index.html
which I'm gonna open in browser.
So test and promises is my folder
and I'm gonna open my index HTML
which has a style sheet associated with it.
And what it does
it allows the user to initiate a long running task
and to display the results.
This long running task will take a few seconds
and allow the resolve or reject
and display a message on the on the webpage.
So when I click the button
there's an on click handler, which runs in code.
It generates a random number between zero and one
and it sets up a timer based on that random number.
If it's a bigger random number, like 0.9
then it gives me a longer delay.
And if it's a smaller random number, like 0.1
it gives me a shorter delay.
So it's like a semi random delay on the timer.
After the timer has finished in my code
I decide whether to resolve or reject.
Okay?
What I've actually got is
I've got some hard coded.
It's like a sample really
dependent on whether the random number is
greater than or less 0.5.
I decide why to either resolve the promise
or reject it based on the random number.
And then I display a message in the window to say,
oh, that particular task was resolved successfully.
So let me show you that.
So I'll start the task.
So the way it works,
if the random number is less than no 0.5 in my code,
then I resolve the promise.
I'll start another task.
So that was less than no 0.5,
that one resolved as well.
That one was gonna fail
because the random number was greater than, 0.5 in my code.
In my example, it rejected the task.
Also didn't notice the timer was a bit longer
because the number was bigger.
I start another one.
Okay?
I'll start another one, that one was gonna pass.
Another one that one was gonna fail
because the number is greater than 0.5.
Okay?
So it's a simple example just to
kind of explain the syntax of promises.
Well, there you go.
What I could do
is I could click the button several times in succession.
When you create a promise,
it does some long running task
but the code returns immediately.
So you can click the button again and again and again.
So I can click the button several times in rapid succession.
Every time the on click handle occurs
it creates a new promise object.
The promise will in the background,
resolve or reject and display a message on the console.
Every time I create a new promise
I've got like an on click count.
It'll know that this is promise one
that's promise two,
that's promise three,
the promises will get resolved potentially out of order.
The longer a promise takes to run
the longer it'll be before it's resolved or rejected
another promise might resolve or reject sooner.
So you can see here, in this example,
I created five tasks,
but they resolved in a different order
based on how long the time out was for each one.
Task one was quite a long time out.
So that took a long time to fail actually
task two was also quite a long time out
but not as long.
So task two completed before task one
because the numbers are smaller.
Task four was the first one to complete
because it had a very small random number.
Okay, so I'm gonna do that just to prove the point.
Up here, let me just refresh the window.
And I'll click the button a few times in rapid succession.
(button clicking)
Okay?
So you can see, depending on whether the random number
is greater than, or less than no 0.5 in my example code,
it'd like cues to resolve or reject
and the bigger the number the longer the delay.
Okay?
Very pretty.
Let's have a look at the code.
First of all,
I've got a code that performs a long running task
and returns a promise object.
So that code is in task dot js, task.js.
Okay, so this is my long running task.
It takes a task number, 1, 2, 3,
and the random number,
which will govern whether it succeeds or fails.
So it creates a promise object.
And in that promise, I give it a piece of work.
Whenever you create a promise object
the constructor for promise always takes a function.
It calls that function immediately.
Okay?
And then returns that promise object.
That promise object gets returned immediately
back to my user interface.
Inside here, I've got a long running task.
So after a random portion of five seconds,
the bigger the random number, the bigger the delay
after that delay,
it will invoke the code here in my set timeout.
So that's where the asynchronous nature comes in
and where the delay comes in.
So after a random amount of time, it will decide what to do.
And it says, well, okay,
if the number was less than 0.5,
I will tell the promise to resolve.
Resolve is a pointer back to a function inside the promise
to say, yes, it worked and here is the result.
When you call the resolve function,
whatever you pass in as a prompter,
that's the success result
that the promise object will report back.
So it'll say something like, task one resolved
or alternatively,
if the random number was 0.5 or above
then the promise will reject.
Okay?
So, this is my function
It will execute some code in the background.
The promise object will either,
eventually be resolved or rejected.
Okay.
So that's my work code.
I've got another file, which has my user interface code.
So let's have a look at that next.
So that's UI case.
So as you would imagine
while I've got a promise count,
that will be incremented every time we do a button click
this is my on click handler.
If you looked at the webpage,
it calls this function whenever I click the button,
increment the promise count
and generate a random number for this particular task.
Oh, it displays a message on the webpage.
In my CSS, I've got some CSS classes.
Let me just quickly show you that.
In my style CSS, I've got a CSS class of info
which displays the blue messages.
Those are the informational messages there.
I've got a class called resolved,
which will display the green messages.
If a promise is resolved.
And I've got a rejected CSS class,
which I apply if the promise is rejected.
And obviously those are these ones done here.
Okay.
So in my use of interface code, first of all
in the display message function,
it takes the name of a CSS class and a message
gets that message area,
which is a div at the bottom of the page.
And it adds a chunk of HTML into that div.
It basically displays another message in the panel down here
in the class that I have specified,
the CSS class I have specified,
like info or resolved or rejected
that will decide whether
the message is displayed in blue or red or green,
and then the message itself.
Okay?
So when I call the display message here
it'll pass in the info class to display in blue.
And the message is,
task one about to start with random number X.
And that's the message that we saw being displayed here.
Okay?
And then it went off
and basically kicked off that asynchronous work
that function returns immediately with the promise object.
Okay?
That promise object will eventually complete
one way or the other.
If it succeeds, you know, five seconds later
then the value that it returns will be a message like this
task X resolved.
So it'll take that value
and it'll display that with the resolved class
to be displayed in green
or alternatively, if my promise was rejected
because the number was too large
then the error message that accompanied the rejection
that error message comes into my cat handler.
And that error message,
I then display with the red font,
like so.
Okay?
So we've seen how to create a promise.
You create a promise
and you have a long function
in that long running function
when it's finished,
you either tell the promise that
it's been resolved with the result
or rejected with an error message.
And then the code that creates the promise can say,
okay that promise that I've just created
if it completes then do this,
if it fails, then do that.
Okay, so hopefully
by now we have a fairly decent grip of how promises work.
What we'll do in the next section
is see how to test that promise code
both for successful completion and for rejection.