Transcript
This transcript was autogenerated. To make changes, submit a PR.
You hi, welcome to Conf 42
Javascript. We're going to talk about JavaScript, the grumpy parts. Why is it so
weird and how can we demystify it? Here's the
part where I tell you, I'm definitely going to post the slides on my site
tonight, but they are online already. Let's head out to roberich.org.
We'll click on presentations here at the top. And here's Javascript,
the grumpy parts. The slides are online right now.
It while we're here on robrich.org, let's click on about
me and we'll see some of the things that I've done recently. I'm a Microsoft
MVP, a Docker captain and a friend of Redgate.
I'm a Cyral developer advocate. So if you're struggling with your data mesh,
I'd love to learn from you. AZ Giftcamp is really fun AZ Giftcamp
brings volunteer developers together with charities to build free software.
We start Friday after work. Sunday afternoon we deliver completed software to
the charities. Sleep is optional, caffeine provided. If you're in
Phoenix, come join us for the next AZ give camp. Or if you'd like
a give camp where you live, hit me up on email or Twitter and
let's get a give camp in your neighborhood too. Some of the other things that
I've done, I worked on these gulp team as a core contributor in version two
and version three. And one of the things I'm
particularly proud of I replied to a Net Rocks podcast episode. They read
my comment on the air and they sent me a mug.
So there's my claim to fame. So let's
dig into Javascript. The grumpy parts we
talked about. This guy I want to thank Jonathan Mills.
He created a talk called a guide to Javascript. Scary side.
And this talk is kind of an extension of the conversation that we had.
After that, if you had a chance to see John Mills in
action, it is a great talk. We're going
to get to the spot where we may hit these edge of my knowledge.
I'm excited to do that. Let's explore comments and concerns
and dig into those things that you want to learn about. And let's
see, can we stump me? That'll be fun.
Javascript this is Brendan Ike.
Brendan Ike wrote JavaScript 25 years ago in ten days.
The code that I wrote 25 years ago is pretty awful. The code
that he wrote 25 years ago is powering the majority of the
Internet. That's amazing. If you want to grab the slides from
roberts.org and you can read more or watch more about
Brendan Ike's journey in creating JavaScript.
JavaScript the cool part is that we now
have Javascript in lots of different runtimes. I bet you
have a JavaScript runtime in your pocket right now.
For Chrome we have V eight. V eight also powers node.
In Firefox we have Spidermonkey. The old Internet Explorer
had the Chakra JavaScript engine, and Safari has the JavaScript core
engine. And the cool part is that each of these engines
has been copied with amazing fidelity, so you
won't find differences in JavaScript in various engines.
Maybe newer features aren't implemented yet, but JavaScript
itself is incredibly consistent across platforms.
Now it was copied with amazing fidelity in
the early days when we were struggling with JavaScript. What we were struggling with was
not JavaScript, it was the document object model,
the DoM. The implementation between JavaScript and
the DOM was really haphazard, and that's been standardized
a lot with HTML five. But that's the part that isn't consistent.
Javascript. The language itself has been copied amazingly
well, including the bugs.
Brendan Ike was interviewed and said about two weeks after he built
it, he noticed a bunch of bugs and he wanted to go back and fix
it. And they said no, there's 40 developers building
JavaScript apps. I bet there's 40 developers right now wishing
these had gone back and fixed them.
But the cool part is that the methodology of JavaScript
is this mechanism where we download our source code into
the browser. Now this is interesting, unlike other things
where maybe we'll create an executable and ship that executable,
or we'll create an image and you don't need all the Photoshop details
and all the layers. By comparison, in JavaScript we are shipping source
code. So the methodology is that that source code
is running in an environment where the developer has already left.
It's a memory constrained area, and so the goal of
JavaScript is to keep going as long as possible.
Now that means that, well, if it finds an error,
it's going to back up and try to see if it can fix it by
inserting a semicolon. So the magic question
are semicolons required? Well yes, the engine
does require it. It's just really good at putting them in place if you don't.
So if you leave off the semicolons, then JavaScript
will help. Let's take a look at
some of the weird JavaScript parts. This is
a talk where Brendan Icke plays a
video called JavaScript Watt and I love this
grab the slides from roberts.org and push play. You will
really enjoy this video. The cool part is this is at Fluentcomp
where Brendan Icke is actually giving commentary throughout the video.
That is amazing. In that video these talk about lets of weird
parts about JavaScript. We're not going to dig into all those, but let's look at
a couple of the weirder ones. Undefined undefined is
just a variable in JavaScript. In later versions of JavaScript it
behave a constant, but in early
versions of JavaScript it was just a variable, so you could
say assign it. That's a great way to break a lot
of programs to assign something to undefined.
Similarly, type of null type of null
is an object. That's weird. Why wouldn't type of
null be null or undefined? Yeah,
that's probably a, but similarly
type of not a number type of Nan. Now as
we look at the types in JavaScript, we have functions, we have objects,
we have numbers, we have strings, we have booleans,
we have arrays. So what type is
not a number? Well, it's kind of in the number family, so I kind
of get that it was organized that way. But is
this a bug? Not sure.
The compiler now a lot of the weirdness that is
JavaScript is based on how the compiler works. Let's dig in deep
and see if we can understand the compiler. Now at each step
we're going to take a look at how this code works. We're going
to think like the compiler to see if we can disambiguate it,
make it make sense. The Javascript compiler is
a two phase compiler. These first pass it
goes and looks for memory that it needs to allocate. The second pass,
it executes all the code. Now there are a whole
lot of modern updates to compilers that'll do tree
shaking and just in time recompilation and comparing hotpaths.
And those are interesting, but still fundamentally it is a
two phase compiler. Grab these slides from robertsch.org,
click on the read more or the watch more link, and you can learn more
about the Javascript two parts compiler.
So here's some code, and let's take a look at how
that behaves with this two parts compiler.
We start by defining a function, and then we'll execute
that function. As we get into that function we go looking for a
variable called foo. If true.
Now in this case variables are defined
with function scope, not curly brace scope. So we've defined a
foo variable and set its value to bar.
Then we console log foo again.
Now when we first look at this, we go well,
how are we using the variable before it's defined?
Yes, let's think like the compiler and see if we can figure this out.
Using the two these compiler, we first look for variable allocations.
So here's one. We've got that variable and it is scoped to this main
function. Okay, second path, let's execute
it. We execute the main function and now we want
to go log the foo variable. Well, we defined it here. It doesn't
have a value set. So we'll console log undefined. Then we'll assign
it to bar and we'll log it again. So we get undefined and bar.
It's much like this. And here's variable hoisting where we've kind
of given ourselves a good interpretation of what's happening.
Now, this isn't actually what's happening. What's happening is that two pass compiler.
But we can give ourselves this kind of mental trick so that
we don't have to think of that. We call this variable hoisting. We pretend
that that variable got defined up here and set to undefined and
now we can reason about it a little easier. Okay, got defined and then we
do it and away we go hoisting.
It's a lie. It's a convenient lie and it works
for us, but it's an artifact of this two
parts compiler. If we think like the compiler and we understand
that two phase process, then variable hoisting is
a lie that we may not need anymore. Or maybe it's still convenient.
So when we look at this and we think like the compiler,
we can kind of understand what's going on. Let's do a lot of
exercises of doing exactly this thinking like the compiler.
First we'll start with variable scope. Let's take a look at what happens when
we define and don't define variables in various scopes.
Now I'm going to define two variables here, one outside these function and
one inside the function. Maybe this is foo one and foo two, or foo
outer and foo inner. Now take a moment,
pause the video. What happens here?
Let's think like the compiler and figure it out.
First we go look for variable allocations. We've got one here,
one here, so we've defined those two foo variables,
second parts. Now let's go execute it. Let's set the outer foo
to bar. Let's define a function, call that function.
We'll set the second variable to bas.
Okay, so we know that variables in Javascript are
function scoped, not curly brace scoped so here we're
going to go look for a foo variable. In our current scope, we find this
inner foo and we set what was baz to bam and let's log
it. Then leaving the curly braces,
let's log foo again and so we get bam again leaving
that function, we'll now log foo and we'll log this outer foo bar.
So we got bam, bam, and bar. Is that what you got?
Let's do it again, but in this case instead of defining
it here, we'll define it here. What happens
in this case, let's think
like the compiler and figure it out. Our first pass is defining variables.
We look for variable allocations. We find outer foo and we find
inner foo and we've got those marked. Next pass,
let's, pardon me, next pass,
let's execute it. So we'll set our outer foo to bar.
We'll define our function and then execute it. We'll set a
foo variable to Bas. Now we're looking for a foo variable in
our current scope. Inside these curly braces we find
this foo variable and it is in scope because these variables are scoped to
functions, not to curly braces. So these variable we set
to Baz. Now inside the curly braces we go looking
for a foo variable and we find that same one and we set what
was baz to bam. We'll console log that, we'll console
log it again and so we get bam twice leaving the function.
We're now looking for an outer foo variable. We find bar,
so we get bam, bam, bar,
is that what you got?
Let's do it again, but in this case let's only define
the variable, but here what
happens here? Let's think like the
compiler and figure it out. Our first pass is to define the variables, so we'll
allocate this outer foo variable. Next pass we'll start assigning
things, so we'll assign it to bar. Then we'll define and then
execute our function. And then we'll go looking for a foo variable.
Now we don't find a foo variable in this current scope, so we'll climb
up scopes. We found one here in these outer scope and
so what was bar is now Baz.
Let's go looking for a foo variable again. We'll find this variable and let's set
what was Baz to bam console log. Bam and bam.
And then as we leave the function we'll console log it again. We go
looking for the variable and we find this one in our current scope that we
set to bam previously. And so in this case we get bam three
times. Is that what you got?
Let's do it again. But in this case we're not defining any variables.
What happens here? Let's think
like the compiler and figure it out. Our first pass, we go allocate variables
and in this case there aren't any. Next pass,
let's start by looking for a foo variable to assign to bar.
Now we don't have a foo variable defined in these scope, so we start climbing
up scopes and eventually we get to the global scope. Now Javascript
is an engine that tries to recover from errors as best it possibly can.
So it says, hey, I'll invent one for you, and it creates a global
variable called foo. Okay, so let's set that
global variable to bar. We'll define our function and then execute
it, and then we'll go looking for a global variable. Now we
don't have a variable foo in this scope, but we can climb up through
outer scopes and eventually into the global scope and find that
variable that we created before. So what was bar is now Baz.
Let's set what was Baz to bam and log it.
And then leaving the function, we will log it again. And so we will log
bam three times. Now we did end up with
a global variable. Global variables are really awkward
because for example, if I create an I variable and
you create an I variable and we both forget to define
them, then well, we'll start to stomp on each other.
That's bad. So let's
do this again. Now I'm going to set foo equal
to bam. What happens here?
Let's think like the compiler and figure it out. Okay, first step,
we look for allocations. We find one here and next
we will execute it. So we'll set our outer foo to bar,
we'll define and these execute a function, we will set our foo,
oh, let's find a foo. We find one in this outer scope.
So we'll set what was bar to Baz inside here,
we will set foo to these value of bam. Ooh, we need
to go find a bam variable. We look in the current scope, there is no
bam in the outer scope, there also is no bam. Eventually we get up
to the global scope, still no bam. So we
get an error here, we can't read the value of an undefined variable
and so we get a reference error. Bam is not defined.
Wait a minute. If we tried to set a variable that didn't
exist, it worked. If we try to get a variable that doesn't exist,
it doesn't work. Yeah, that's kind of weird,
but we understand now why it is. Javascript tries to correct whenever
it can, and it can create new variables. That's easily,
that's easy, but it can't read from variables that aren't defined.
So this fails. If ever you've put a console log
right above the variable that you thought you were defining, and you
actually weren't defining it, you might have seen this error. So Javascript
will stop here and that's all we'll get.
Next up, instead of VAR, let's switch these
for let is new in es five and allows
us to create functions or create variables that are scoped
to curly braces, not to functions. Now this may feel a little bit more
natural if ever you've used curly brace style languages like C sharp,
Java C, or C plus plus. So what happens
here? Let's think like the
compiler and figure it out. We start by defining by
allocating variables. So we'll allocate our outer foo and our inner foo.
Then let's execute, we'll set our outer foo
to bar and then we'll define and then execute this function.
Now we go looking for a foo variable. Now we don't have a foo variable
defined in these scope. Let defines these associated with
a curly brace. So that doesn't exist yet. So we find this outer function,
this outer variable, and we set what was bar to Baz.
Now inside the curly braces we'll define a foo variable that is scoped
to these two curly braces. Let's set its value to bam and console
log bam. Now as we leave these curly braces, this inner foo
disappears and now we're left looking for a foo.
We find this foo, this outer foo, and so we log baz
finishing our function, we will log the outer foo again and we get Baz.
Bam, baz, baz, is that what you
got? Now let's
comment out this variable. What happens
here? Let's think like the
compiler and figure it out. We'll allocate this inner foo variable and
then we will define and then execute our function. We're looking for a foo
variable in the current scope. We don't find one. We climb up to the outer
scope, we don't find one there. We keep climbing until we get to the global
scope, not finding one. We will create one, a global variable,
and we will set its value to Baz inside the curly braces.
We'll set our inner foo to bam and console long bam,
leaving the curly braces this inner foo gets garbage collected and now we're
looking for foo. We'll find our global variable that we set to Baz.
Now leaving our function, we're looking for a variable called
foo. We will find that global variable and we will log Baz
again. Bam. Baz, baz, wait a
minute. We just created a
variable that leaked outside of its current scope.
Yeah, you're right, because we didn't define this variable,
it wasn't scoped to either this function or this curly brace,
and therefore we leaked it into the global scope. There's a memory
leak in Javascript now instead
of let, what did we
do? Oh, now let's define this let here.
We want to fix our mistake and define this variable
inside here. What happens here?
Let's think like the compiler and figure it out. We start out looking
for defining and then executing our function.
We will set our foo variable to bath inside this
curly brace. We'll set an inner foo to bam, console log.
Bam. As we leave, this inner one gets garbage collected and
our outside one is Baz. And then
as we leave we're going to look for a foo variable. Now the goal
is to console log it. And so we climb up through various scopes, we get
to the global scope, still don't find it, and we get a reference error.
Foo is not defined because we correctly allocated
our variable here. Then we get a reference error as we would expect,
rather than just silently leaking that variable into place.
It's really important for us to define our variables.
Now let's flip over from let to const. Now the cool part about
const is you can't reassign it. Now const, you can't reassign
the pointer to that object, but you can still mutate the
object. In this case we're using
value types instead of reference types, and so we can't
change what foo points to. Okay,
what happens here? Our first pass, we will
allocate some variables. Here's our outer foo. Here's our inner foo.
Next pass, let's execute it.
We'll set our outer foo to bar. We can't change that value
anymore. We will define and execute our function.
We go looking for a foo variable. We don't have one in this
current scope because it's const scope to curly braces.
So this inner foo doesn't exist. So we try to set
foo equal to baz. We find this outer foo
and we try to set it. It's a const and it won't. And we get
a type error assignment to a constant variable. Now this is perfect.
If you're targeting es five or above, you will get this error.
But if you're using Babel and webpack to transpile this
into a lower form of Javascript,
then it will try to do as best it can, but it
can't catch this assignment under the hood,
it will set it to VAR. So if you're upgrading
your project from es three to es five, and you're modifying your
Babel config to maybe spit out Es next, and suddenly
you get a whole lot of these errors. It's not the change in Babel that
caused this, but rather that you were transpiling
all of the const to Vars. And well,
parts aren't read only. So types you need to go fix
your const to make that happen. Now we
got to look at a lot of ways of defining and not defining scopes
in interesting ways. Let's take a look at this.
This is the thing to the left of the dot. And I really like this
definition. It's very concise. Click read more or
watch more as you grab the slides from roberts.org to learn more.
So let's take this for a spin. Now, we have this console log
where we're going to grab this name and we have this speak function.
Yes, we could have defined it in place in each object, but for simplicity,
we'll just define it out here. What happens here?
Well, we start out saying a global name. So we'll speak.
And so this is our global object and we'll
do this. And so we'll get ninja right here for
object one. This is the object that's these thing to the
left of the dot. And so we'll get Doctor and then Skywalker.
Ninja Doctor Skywalker. Perfect.
Now, we can create variables
from functions. So let's grab the object one speak and make it an
object speak variable. Now, when we do object one
speak, it works as expected and we get Docker Doctor.
But here, object speak, what is the global
variable? Well, it's undefined. Now, I'm assuming that
something defines name, otherwise we would have gotten a reference error.
But because I removed the thing to the left of the dot,
I've changed what this applies to.
Similarly, if we do this in
a page, let's document getbyid the button, and then we'll
button add event listener, click here's our speak event and we'll console
log this id. What's the thing to the left of the dot?
It's the button. And so what gets passed in as
this is the button, because we got it by id. When we output
this, we get the button. Perfect.
Now, I want to not show the name right now.
Rather, I want to show it after a little while. So I'm going to set
timeout. Now, the interesting thing about set timeout is it will
create a new scope. So when we do
this, what happens? Well, we're going to find ninja,
and then we'll speak. We'll set timeout in 100 milliseconds. We'll go
look for the thing, this name. What's the thing to the left of the
dot? Well, it's the global object. We created a new scope,
so we get ninja. Now, object one,
speak. We'll wait 100 milliseconds, and then we'll look for
the thing to the left of the dot, which is the global object, and we
will get ninja. Oops.
Because we created a new scope with this function,
then we lost the context of the thing to the left of the dot.
Let's see how we can control it. Now we can use
call. Call is really interesting. Now,
I've not defined an object here or not defined the speak,
but I can say object one. Speak, call,
and I'll pass in what I want this to be. In this
case, it's OBJ two. So now when
it gets passed in, I've overridden this, and it's now ob two.
And so I will correctly get Dr. And Skywalker.
Perfect. Next up, let's use this
call to try and fix our set timeout bug. Now,
the interesting thing is this executes the function right away,
so I will get the right answer. But I didn't wait
100 milliseconds. Let's see if we can delay
these thing rather than just calling it right away.
Let's see if we can wait and call it later. We have
bind. Now, this isn't these actual syntax of bind, but we can kind of think
of it these way. We'll have this fake bind function we'll pass in
our function and what we want this to be. And we can return a
new function that later will call passing in
what we want this to be. So now we have this new function that we
can call whenever we want. And this is already overwritten.
That's cool. So let's use the real bind.
Here's the real syntax. Object one, speak, bind, and we pass in the
this. And so now we will
get the values as we expect. Doctor and Skywalker.
Perfect. Let's see if we can use this bind
mechanism. Oh, you may find content in your code that says
obst two speak, bind obst two. Basically, what they're
trying to do is enforce that this object has overridden this
in all these ways that it needs to so that it never loses
context for what it's after. If you see that code in
your code base a lot,
that's exactly what it's doing. So let's use bind
to see if we can solve this problem. Now,
we'll start out by calling speak. It's going to create a new scope,
but we've overridden that scope with what this is while
we're inside here. This is the global function. And so in 100
milliseconds, we output ninja. Perfect.
Now, when you call object one speak, what comes in here?
Object one is this. We'll set timeout. We'll override
the global that it would assume with this, which is object
one. And in 100 milliseconds, we get the correct answer.
Great. Bind was able to help us solve
our set timeout error.
Let's use arrow functions. Now, the cool part about arrow functions
is it defines a function in a really
these syntax, but it also sets
this at the point where the function is created.
So it's much like calling dot bind this,
right? As we define it, we can think of this as
equivalent to this. Okay,
so knowing that the arrow function is going to bind this at the point where
it's instantiated, we might be able to use or misuse
that. So let's create this speak function, and we
will bind it to this name. And let's see what
happens here. Well, when we call speak,
we get to here. What's the thing that got bound when it
was created? It was the global object. So speak, we get ninja.
How about object one speak. When we call object one
speak. Then it comes in here. This was defined with the
global object in place. And so we also get ninja
rather than Doctor or Skywalker Ninja. Three types.
That's not great. If ever you've done a find and replace
in your code base, changing from
function to arrow functions, and these, your app doesn't work anymore.
This is exactly what's happening. You've defined this in ways
that you didn't expect. That's totally fine. Now that we understand
how that works, we can use that correctly.
There are times when we want function where we don't want to override this,
and there's times when we do want to override this, where we can use that
terser syntax. So let's use
that. Well, we want to say obst two speak.
Bind obs two to try and get our thing.
But we've already created this envelope and we've baked the global
scope into it, so we can put it in another envelope and
try to set it to object two. But as we open the
envelopes, eventually the inner envelope still has this
set to the global object. And so we can't fix this
with a dot bind. We've already bound
this name into place. Even if we have an outer envelope that
changes it, the inner envelope still has it set to
the global object.
Okay, so let's see if we can use arrow functions
here to solve our timeout concern.
What happens here? Well, we're going to start off, we're going to
call speak, what comes in here? The this right now is the
global object. We will set timeout and we'll bind this function
to this, which is that global object. In 100 milliseconds
we will execute this name, object one
speak, what comes in here? The this is object one. And then
we set timeout. We've baked it into place and so we got object
one's name. So we get ninja and Doctor.
Perfect. We were able to use these arrow functions
binding of this to be able to get that into place in
a really elegant way. The event
loop. When we look at the event loop,
we can see some really interesting things. And I like this site
that allows us to explore how the event loop works.
Now this site is a great way to be
able to visualize mechanisms. We have our
call stack things that are executing right now. We behave a callback
queue, things that have finished, and then we have stuff that's waiting on
external pieces as the external pieces get done.
For example, if I click the button, then that will come into this
callback queue. And when the call stack is empty, it will grab the next
thing from the callback queue and be able to execute it.
So we could take a look at this mechanism and we
could run that code, setting it here in place,
save and run. Now this does take a bit to execute, especially because it's
waiting a second. But we can see how it's counting through each of these,
setting it in place when 100 milliseconds,
when 1 second finishes, it's in this callback
queue, but it's not executing yet because it's still counting
down. This is that great example of what
is the console log once we get done here? Well, these are all
bunching up. Eventually, when it finishes counting
up and finishes queuing things, it'll be able to drain
these and the answer by then will always be
eleven or ten rather, so we'll console
log ten times. I love this mechanism of
being able to visualize that. Now that the call stack
is empty, we're starting to pull data from the callback queue and
sticking it in the call stack to do interesting things. Now this
call stack mechanism is interesting, and we can use that
to be able to visualize what we're doing. Here we
have the GUI thread that is executing that content. We have the list
of things that are ready to go in that callback
queue. And so every time the GUI thread finishes,
it'll go grab the next thing out of the callback queue and execute it.
And then we have those other things waiting for something else.
If that event happens, then they'll go into the callback queue.
So if our GUI stack is doing something really intense looping
from one to a million, then it's never going to run those callbacks.
Click on this read more, or watch more as you grab the
slides from roberts.org to learn more about the event loop.
When we talk about node servers, we have in effect
a bunch of these different mechanisms. Now this is definitely the logical
implementation, not the physical implementation, but we can think of every request
as having their own GUI thread, callback queue,
and web API callbacks.
So Javascript is single threaded. So it'll go look at
this request and it'll drain its current stack, and then it'll
go to these request and drain its current stack, and then it'll go to this
request and drain its current stack and wander all the way through. If it
gets to a request that has an empty callback stack, it will grab the next
thing from its done stack and be able to accomplish that.
So if I've got a request over here that's counting from one to
a million, or doing a big computation on an image, then that's
why all of these requests are blocked. Now,
JavaScript is single threaded, so we need to yield that thread and let the
node loop go around that circle and go grab all of these next
things and then continue counting in on our image.
If ever you've seen a set timeout zero, or if you've seen a process next
tick that you've awaited, and you're like well, why would I wait 0 second
just to be able to get it? That's exactly that. You're yielding the thread so
that other threads can catch up and you haven't locked out all of the other
requests.
Async and await async and await is really neat,
and it's a pattern
clearly stolen. I mean inspired by c sharp.
C sharp uses async and await over the top of the task. Parallel library
and JavaScript uses async and await over the top of
promises and generators. So it's these
resumable state machine that is created by the compiler.
It knows what step it's on and when it comes back in it can continue
on with the next step. That's perfect now because
it's built on top of promises and generators.
Pardon me. We have a great interop story between promises
and async and await. Let's take a look at that.
Here's a promise based code. We have return new promise. We have
the resolve and reject method and once we're done doing our thing we
will resolve it with those results. We can then say then.
And we can call our various libraries with catch at the end.
Now here's a library that we might have built in the promise days and
now we want to async and await it. Well,
let's take a look at that. Let's create an async function and
these we will say await that async function and now
we can return our results. Now do
we need to wait until we do a big bang refactoring to
get all of our promise code into async and await code? No, we don't.
The cool part about async and await is now we get to
use actual catch. The state machine understands
what state it's on and it can throw and catch
exceptions in the normal way. It looks a whole lot
more synchronous than our thenathon. That's pretty cool.
So promise calling an async. Here we have an async function.
Now if we call our async function but we don't await it and
we take a look at what is these response? The response
is a promise. Well, we know how to handle promises.
So if we behave a new async function that we need to call from legacy
code, we can dot these it.
Here's our async function and we're just saying dot these on that async
function to continue on with our legacy code. That's perfect.
Let's see if we can do it the other way. We have a legacy promise
function and we want to call it from async and await code. Well,
let's go call it. What do we get back? We have a promise. We know
how to await promises. That's what we were doing with async and await.
So let's await this promise based
code. Now we have new async functions calling legacy
promise functions. We didn't need to wait for that big bang refactor.
Async and await its interop with promises is great
because under the hood async and await are just promises.
So how would we do many things in parallel? Understanding now
how async and await and promises work together?
Here's this long running task, and I don't want to await
these previous one before I launch the next one. So I'm going to call
all these libraries, notice that we're not awaiting any of them.
And now what do I have? I have three promises we
can use promise all to wait for,
to turn this promise into an array of into
a new promise that will return an array of results once it's
done. And so let's take this promise all and we will await
it. Now we get three results.
All three of these happened in parallel. Well, Javascript is
still single threaded, so it's waiting
for all of them to finish. I've launched all three and
if each one takes 1 second to execute, I may be done in
1 second instead of these seconds that interrupt between async and
await and promises is beautiful here. Now I can just return the results.
Javascript. Brendan Ike built it 25 years
ago in ten days. I don't know about you,
but Javascript is a pretty excellent place to work. Good job.
Good job, Brandon. I'll be at that spot
where the conference has designated Q and A or hit me
up on Twitter at robrich and you can grab the slides online
right now@robrich.org. Thanks for joining us for
Conf 42s Javascript.