Conf42 JavaScript 2021 - Online

JavaScript the Grumpy Parts

Video size:

Abstract

We love JavaScript, but we must admit: it’s weird. Why does this behave as it does? How does variable scope work? Why do we have such comical behavior when comparing mixed types? Let’s pull back the covers of these scenarios, and learn how it truly works. You may find a new reason to fall in love with JavaScript.

Summary

  • Conf 42: Why is it so weird and how can we demystify it? AZ Giftcamp brings volunteer developers together with charities to build free software. If you're in Phoenix, come join us for the next AZ give camp.
  • This talk is kind of an extension of the conversation that we had. 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.
  • Brendan Ike wrote JavaScript 25 years ago in ten days. The code that he wrote 25 years later is powering the majority of the Internet. The language itself has been copied amazingly well, including the bugs. Let's take a look at some of the weird JavaScript parts.
  • The Javascript two parts compiler uses function scope, not curly brace scope. If we think like the compiler and we understand that two phase process, then variable hoisting is a lie. It's a convenient lie and it works for us, but it's an artifact of this two parts compilation.
  • Let's set Baz to bam and log it. And then leaving the function, we will log it again. Now we did end up with a global variable. Javascript tries to correct whenever it can, and it can create new variables. But it can't read from variables that aren't defined.
  • 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 flip over from let to const.
  • Use these slides from roberts. org to learn more about defining and not defining scopes in interesting ways. Let's see how we can create variables from functions. Next up, let's use this call to try and fix our set timeout bug.
  • Let's use arrow functions. It defines a function in a really these syntax, but it also sets this at the point where the function is created. When we look at the event loop, we can see some really interesting things. This site is a great way to be able to visualize mechanisms.
  • Async and await is really neat, and it's a pattern clearly stolen. Inspired by c sharp. Parallel library and JavaScript uses async and await over the top of promises and generators. We have a great interop story between promises and await.

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.
...

Rob Richardson

Developer Advocate @ Cyral

Rob Richardson's LinkedIn account Rob Richardson's twitter account



Awesome tech events for

Priority access to all content

Video hallway track

Community chat

Exclusive promotions and giveaways