So we learned a lot about async code and that is crucial knowledge you need as a Javascript web developer, no way
around that, you need to understand this.
Now with this out of the way, let's have a look at readability,
this code here can be cumbersome to read, right?
If we have such code where we have callbacks nested into each other, like for example here where we have
some callback with setTimeout with another callback again then maybe another function that uses
yet another callback,
then we enter something which has a nickname of callback hell because it gets cumbersome to read and
maintain, it can be hard to track
what's nested in where,
which variables can access where, this is really not nice code to look at.
Now thankfully Javascript has a solution for that and that is the concept of promises. Promises
allow us to write cleaner code because they look like this.
We have some task, then we used the special then keyword,
we then pass a callback to then
but then if we have another task that depends on the first task, we simply add another then block instead
of nesting it into each other
and therefore we have only one level of nesting here
instead of having multiple levels and that makes our code way more readable, let's have a look at that
in practice.
Unfortunately setTimeout and getCurrentPosition have no promise version,
so we can't add
then after that and try to use that promise approach then. More modern web APIs offered by the browser
typically embrace promises and often only support promise syntax but these older functionalities, like
setTimeout which have been around for forever almost,
well these still use callbacks. Now we can actually wrap them into promise support code if we wanted
to and that's what we'll do here to also understand how a promise works internally. Now later in this
course, we'll also see functionalities built into the browser that natively embrace promises.
So let's start by adding a new function here and I'll just name it setTimer, to not to clash with set
timeout and
this can be an arrow function or created with a function keyword, up to you
and here in set timer, I want to get the duration as an argument, I'll need that and now in here, I'll
call setTimeout and pass the duration as a second argument. The question is what do we do in the first
argument? What do we do here?
Well we have to call a function here, as I said there is no way around that but now I have the callback
function here in this separate function and I'll later be able to reuse that in the places down there
to kind of make that easier to work with.
So now we have setTimeout here and now what we have to do or what we can do here is we can build a
new promise,
a promise is in the end an object with the functionality or with the idea of having such a then
method which you can call on it.
So here we can create a promise and you can store it in a constant with any name by calling new promise,
just like that, promise is the constructor function or the class built into Javascript and therefore we
can construct it like this. Now the promise here itself takes a function as an argument, it takes
a function, the constructor takes a function and this is actually a function
the promise API so to say will execute right away when this promise is constructed.
So when we build the promise here, this function which we pass to the promise constructor is executed
right away, it's called from inside the constructor you could say and it's a way for us to configure
what this promise should actually do, what it should wrap itself around.
This function takes two arguments, so this function we pass to the constructor, this function here, takes
two arguments and each argument itself actually is a function. It's a resolve function,
therefore typically called resolve and a reject function, typically called reject but you can name these
parameters however you want,
it's up to you, it's your code here.
Now in the function body, as I mentioned this executes right away when the promise is created. In the
function body here, you can define what should happen
and here I actually want to set the timer, I can access the duration because of the scoping thing you
learned with functions and now the timer is set
when this promise is created. Now in here, we have our async code then, this callback in the timer will
only execute once the timer is done
and after creating this promise, so not after the timer is done, only after creating the promise where
the timer is then kicked off, I will return the promise here so that I can use it wherever I call
set timer, it's returned as a return value of this function.
Now here inside of setTimeout, I will call resolve,
so I'll use this first argument which I said is a function by simply executing it. Now we'll not pass the concrete
function here into promise, instead that is built into the browser. The browser executes this function
for us when it creates a promise and it passes the resolve and the reject functions into this function
here for us.
So the resolve function is coming from the browser, from the Javascript engine to be precise, that is
passing in that resolve function and it's a function which internally will mark this promise object
which is created here in the end as resolved, so as done
you could say and I call resolve here once the timer is done. You can
also pass a value here to resolve
if you wanted to, for example some text but that can be anything, can be an object, can be an array, a number,
whatever you want,
here it's some text, so I pass this to reolve, for the moment I'll ignore reject.
Now we have set timer, now that I'm down here,
we can use set timer, I can call set timer, not set timeout but set timer,
so my own function here, I call this in here and now,
we don't pass a function to set timer because set timer doesn't want the function, it just wants
a duration.
So here we could still pass into 2000 seconds in milliseconds and those will be added to the
wrapped set
timeout. Now set timer does return a promise in the end as my tooltip also shows here, it returns a promise
because that's what I do inside of set timer, I create a promise and I return it.
Now on this promise object, you can call then, you can call this then method and it will basically execute
whenever this promise resolves. Now promise can also resolve more than once, more on that in a second,
for now it resolves once resolve is called here and that happens when the timer is done,
in this case here, that's the logic we wrote in this promise configuring function which we passed to
the promise constructor.
Now in here we also get any data that might be resolved, in this case that will be the text
and then here, I can console log the data here and maybe also the position data here if I wanted to. Now
what you'll see is that if we save that and we reload, if I click track me and I allow this, you will
see it again will take until we have the position and until the 2 seconds are over
but thereafter we see our location but we also see done
and that of course is the text coming from inside my promise.
What we did here is sometimes also called promisifying a built-in API,
I'm wrapping the set timeout API with my promise logic so that I
yes
have some extra effort up there,
it's a bit more complex code but then I can always use the timer here instead of that callback way here
with just my promise
way. I can always call then here now and then have my callback function registered here, timer done
and whilst the benefit might not be super obvious when we just do that for the timer,
imagine we have something similar for get current position and so on and we then just have a couple of then
calls chained after each other as it's called and that's actually what we'll have a look at next.