Jonas: So, at this point of the section,
you know all about consuming promises,
but we have never actually built our own promise.
And so, let's do that in this lecture.
And let's go back to our lottery example from the slides,
and basically simulate a lottery using a promise here.
And remember that, in that example,
a fulfilled promise means to win the lottery,
while a rejected promise means to lose.
So, let's get to work,
and we create a new promise, using the promise constructor.
So that's new Promise, like this.
So, just like many other built-in objects.
And so, what this means,
is that promises are essentially,
just a special kind of object in JavaScript.
Now, the promise constructor takes exactly one argument,
and that is the so-called executor function.
So, we need to pass in a function here.
And so again, this one is called executor.
Now, as soon as the promise constructor runs,
it will automatically execute this executor function,
that we pass in.
And as it executes this function here,
it will do so, by passing in two other arguments.
And those arguments are the resolve,
and the reject functions.
So reject, like this.
So, we will use them here in a second,
but for now, let's actually build this executor function.
And also, we should probably store the results.
So this new promise in some variable,
so, lotteryPromise,
okay?
So all of this here will create a new promise,
that we're gonna store into this variable.
So, it's just like, for example, the fetch function,
which also creates a new promise.
Now, this executor function that we specified here,
is the function which will contain the asynchronous behavior
that we are trying to handle with the promise.
So, this executor function
should eventually produce a result value.
So, the value that's basically gonna be
the future value of the promise.
And so, let's do exactly that,
right here in the executor function,
and starting with a simplified version.
Now, in our lottery example,
let's say that we actually win in 50% of the cases,
and lose in the other 50%.
So, very simplified example,
just to make this a bit more fun.
And so, what I'm gonna do,
is to simply generate a random number,
which remember is gonna be between 0 and 1.
And so, I can simply say, if this number here,
is greater or equal, than 0.5,
then, I want to call the resolve function.
And so now, this is where this resolve function,
that was passed into the executor function, comes into play.
Alright?
So, in this situation here,
we say that we win the lottery,
and so therefore, that means a fulfilled promise.
And in order to set the promise as fulfilled,
we use the resolve function.
So, basically calling the resolve function like this,
will mark this promise as a fulfilled promise,
which we can also say a resolved promise,
and that's the reason why this method here,
is called resolve.
Now, into the resolve function here,
we pass the fulfilled value of the promise,
so that it can later be consumed with the then method,
right?
So of course, we are going to handle
the result of this promise,
just like we handled any other promise
with the then method.
So again, whatever value we pass
into the resolve function here,
is gonna be the result of the promise
that will be available in the then handler.
And so in this case, let's simply pass in a string here,
and let's use some emoji,
again to make it a bit more fun.
And so, now let's handle the opposite case.
So where, we basically want to mark
this promise as rejected.
And so, as you can imagine for that,
we can call the reject function.
Then into the reject function,
we pass in the error message,
that we later want to be able in the catch handler.
So, in the catch method,
right?
So here, let's just say you lost your money,
and then, just some poop emoji.
Alright?
So, give this a save here.
So just to quickly recap,
before we consume this promise,
here, we created an executor function,
which is gonna be called by this promise constructor,
as soon as it runs.
So, basically immediately, right?
Then, the promise calls this function,
and passes in the resolve and reject functions,
so that we can then use them,
to mark the promise as either resolved,
so, as fulfilled, or as rejected.
And so, you see that this promise
is eventually going to move to either the fulfilled state,
or the rejected state.
So, we always need to make sure
that the promise ends up in one of these two states.
Alright, and so now it's time to actually try this out,
by consuming this promise that we just built.
So, lottery promise, is going to be a promise object
at this point.
And so then as always, we can call the then method.
And then, just like before,
the then method needs a callback function,
that is going to be called with the resolved value
of the promise.
So, let's call this res here,
and then, let's simply log it to the console.
Okay?
And of course, once again, this could be any name here,
right?
And now, let's also catch any errors.
And so here also, as always,
we will simply log it to the console as an error.
Now okay, and so that's actually it already.
So what do you think this res value here is going to be,
or this error is going to be?
Well, as I just explained before,
the resolved value of the promise,
is going to be this one, that we passed in here.
And so therefore, the value that we're gonna log,
in the case that the promise is successful,
is going to be exactly this string
that we passed into the resolve function,
and the same is true with the error.
So the error here is going to be, simply this one.
Because that's the string,
that we passed into the reject function.
Okay?
So let's see, and indeed we get our error.
So, you lost your money.
And so, as we keep reloading,
we should then see these different states,
according to this random number that was generated here.
Great, so now we won.
And so, as we keep doing this,
we can see the different states that the promise will take.
So that's amazing, but however,
right now, this is not really a synchronous yet, right?
So, let's actually simulate this lottery draw
by adding a simple timer.
And so, this timer will then simulate
the time that is passed between buying the lottery ticket
and actually getting the result.
So, let's add a setTimeout here.
So with a simple callback function,
and let's run it for two seconds.
And here, we will simply take this code and put it here,
and then we can also immediately
lock something to the console,
like, lottery draw is happening.
And then, let's add like a crystal ball here.
So, that's exactly also what we had in the slides.
Alright?
And now, another thing that we can do is to,
instead of passing just a string here,
we can also create a new error object.
So basically creating a real error,
and so, that's a little bit better.
So, just like this.
And so with this, we made this whole promise here,
make a little bit more sense,
because now by using this timer, we did actually encapsulate
some asynchronous behavior into this promise.
And so, that's the whole point of promises
in the first place, right?
So let's give it a save to see what happens.
So immediately, we get this here,
and then, after two seconds the promise was resolved.
And so then here, we handled that result,
and logged it to the console.
Let's try again, and of course,
again, this one comes immediately, and we win again.
Let's see if we can lose.
Apparently we can only ever win.
Nah, but here you go.
So, now we get the error message just like before,
but we also now see that it's an error,
and it also tells us where this error is coming from.
So, right at line 292.
So, that's right here.
And so indeed, actually creating a new error object,
is actually a bit better.
Great.
So, this is how we encapsulate any asynchronous behavior,
into a promise.
So, how we abstract it away in a very nice way,
just like we did here, right?
And then, all we have to do,
is to consume that promise like this.
And so this is a really nice and helpful pattern.
Now, in practice, most of the time,
all we actually do, is to consume promises.
And, we usually only build promises,
to basically wrap old callback based functions,
into promises.
And this is a process that we call promisifying.
So, basically promisifying,
means to convert callback based asynchronous behavior,
to promise based.
Alright?
So, let's see that in action a little bit.
And so, what we're gonna do,
is to actually promisifying the setTimeout function,
and create a wait function.
Okay?
So, let's create a function called wait,
and this function is going to take in
a number of seconds.
Okay?
And so now inside of this function,
we will actually create and return the promise.
So, usually that's always what we do.
So creating a function, and then from there,
returning a promise.
And so this will then encapsulate
the asynchronous operation even further.
So, essentially that's also what the fetch function does,
right?
So, it's a function that returns a promise,
and so, that is exactly what we will do,
here with this wait function.
So, in a sense, this here is a more real world example.
So, promisifying
setTimeout.
So, as I was saying, we are going to return a new promise,
and then, our executer function as always, and then resolve.
And in this case,
we actually don't even need the reject function.
And that's because,
it's actually impossible for the timer to fail.
And so therefore,
we will never mark this promise as rejected.
And so, here we don't even need to specify
that reject parameter.
Alright?
So, it's just like the array methods, like map,
which always receive three arguments,
but most of the time, we just use one or two of them, right?
And so, this is similar.
But anyway, all we have to do now, is to use setTimeout.
And then here the callback function,
that we want to be called after a certain time,
is exactly the resolve function.
So we can simply do this,
and in this case, we're actually not even going to pass,
any resolved value into the resolve function,
because, that's actually not mandatory.
And so, in the case of this timer,
it's also not really necessary.
And so, in the case of a timer,
it's also not really necessary to wait for some value,
right?
So in this case, all we want to do,
is to basically make our code wait,
and so, no resolved values are needed.
Now here we want to run that timer
for a certain amount of seconds,
so we need to multiply that by 1000.
And so, that's actually already it.
Now, we could improve this even further here,
or I mean, just make it smaller by using arrow functions,
and you can do that if you want to have some fun with that.
But for now, I will simply now consume this promise.
So, let's call our wait function.
Alright.
And so, this will now create a promise,
that will wait for 2 seconds,
and after these 2 seconds, it will resolve.
And so, we can then handle that.
And then, here in our callback function,
remember we are not going to receive any resolved value,
so we just leave this empty.
And then, I will simply log, I waited for 2 seconds.
And so, here in this callback, we could now run any code,
that we wanted to be executed after 2 seconds, right?
And then, let's actually wait 1 more second,
and so just like before,
we now have to return a new promise here.
So, return wait
and this time, just 1 second.
And so, this is exactly what we did before,
when we wanted to chain two sequential AJAX calls,
using the fetch function, right?
So, in the result of the first fetch,
we would create a new fetch and return it.
And so, that's what we're doing here.
And so then therefore, all of this returns a new promise,
and then, we can one more time handle that.
And let's just say again, I waited for 1 second.
Alright, so give it a save.
So, this one waited for 2 seconds,
and this one for 1 second.
And of course, we also still get the result
from the previous one,
but for now, this is here, what we are interested in.
And so now with this, we have once again a nice chain
of asynchronous behavior that happens nicely in a sequence,
and all without the callback hell.
So before, I actually showed you what happened,
when we had multiple timers,
and so basically, we could do now this same thing,
like this.
So, let's just copy it here as a reference.
And so, this example here would be this.
So,
1 second passed.
So, let's just override this one here,
and then here we can simply,
duplicate this a couple of times.
So, 2 seconds passed,
3 seconds,
and here,
4 second passed.
Alright?
And so, that's going to be exactly the same result,
as we had here.
Of course here it's 4,
but nevermind, that doesn't really matter.
What matters, is that now,
we no longer have this ugly,
and difficult to understand callback hell,
but instead, we have this nice sequence
of asynchronous behavior.
Now finally, there also actually a way, to very easy,
create a fulfilled, or a rejected promise immediately.
And we had actually already done that
in the previous lecture,
but it's always good to know that we can do this.
So, let me show it to you again,
so we can use, Promise.resolve,
And so, basically this is a static method
on the promise constructor, right?
And so here, we can then pass in the resolved value.
So, just like we would pass the resolved value, right here.
Okay?
So, again the difference,
is that this one here will resolve immediately.
So here, it doesn't matter.
So just abc, and then we can handle that.
And so again, the values here don't matter.
And then, we can also do the same with reject.
Let's just duplicate this here actually.
So reject, and here the then is not necessary,
because there will be no resolved value anyway.
And so, we can just catch it like this.
And so, these two here should now appear
at the very beginning.
Well actually they don't.
So, let's see.
Oh, actually here they are.
So here is abc,
and then abc, here let's just create a new error.
Alright?
And so indeed, here we got, lottery draws happening,
which comes from the previous promise.
And then after this we have abc,
and then the problem that we created here in the end.
Alright, so this is how we built our own promises,
and how we promisify,
a very simple callback based asynchronous behavior function,
such as setTimeout.