Check out a free preview of the full The Hard Parts of Asynchronous JavaScript course
The "JavaScript Code Execution" Lesson is part of the full, The Hard Parts of Asynchronous JavaScript course featured in this preview video. Here's what you'd learn in this lesson:
To ensure a proper and shared foundation for upcoming lessons, Will reviews code to understand what happens when JavaScript executes or runs.
Transcript from the "JavaScript Code Execution" Lesson
[00:00:00]
>> Will Sentance: Here we are, Hard Parts of JavaScript. The foundations we have to understand in order to get to the Hard Parts are gonna feel at times a little bit trite, a little bit trivial. I've hoped you've been to Hard Parts before, you'll even gonna feel, hold on, I've seen this stuff before.
[00:00:20]
Our first about 30 minutes or so is going to be material that, if you've been to Hard Parts before, you'll recognize. Because that is the JavaScript engine and how it works, it's universal, but we've got to lay these foundations out. And by the way you're going to see code where you're going to go yeah, yeah, thanks.
[00:00:39]
I get how this code is running, I get what it's doing. But we're gonna see it, and it's gonna empower us to then solve all the hard parts to come. All right.
>> Will Sentance: Let's go, here it is. We're gonna whiteboard through all of our code's execution just as the JavaScript engine runs it.
[00:01:01]
We do that, there can be no gaps in our understanding. We're gonna step through line by line, and we're gonna map it up on the whiteboard the whole time. So with that in mind, what happens when JavaScript executes, runs my code? There's two halves, and I'll tell you straight away.
[00:01:18]
There's two halves to the process of executing code. One is literally the ability to walk through the code line by line by line. That is known as the thread of execution. And all that is the processing ability to take line one, do it, whatever it says to do.
[00:01:38]
Take line two, do it, whatever it says to do. Take line three, do it, whatever it says. It's executing, doing the code, blah, blah, and it's threading its way down our code. By the way, in order, top to bottom. Simultaneously, the other part that's required to run our code is a place to store the bits of data that we announce as we go through our code's execution.
[00:02:02]
So you can see in line one, we're announcing, then we're gonna store num as the label for some data three. And so we're gonna map these on the whiteboard, which will be a fascinating experience. Let's see how it goes line by line, starting with line one. I'm gonna call on Paul.
[00:02:21]
What are we doing here in line one? What are we actually doing?
>> Paul: We're saying allocate some data to global to a constant called num, and then toss an integer 3 onto that?
>> Will Sentance: Well, that seems like a very intuitive description. So we are in our memory. In our memory, we are declaring a constant.
[00:02:48]
Just remember, that means a piece of data where we're not allowed to change its position in memory. So we can't suddenly replace num's value with 4. It's now set for the running of our application, num is set to the value 3, excellent. Michelle what does our next line of code here is saying to do?
[00:03:08]
>> Paul: The next line of code is also creating something in memory that we're calling-
>> Will Sentance: All right everybody we're being very precise, this is precise [LAUGH] go on what's it called? Called variety, excellent. Named multiplyBy2, we're declaring the function multipliedBy2. In JavaScript functions that means the entire functionality is our signed as values.
[00:03:33]
Just like the number 3 we're storing in memory, the functionality, the function definition of multiplyBy2. I'm not gonna write the whole function definition out on the right-hand side here. Instead, I'm gonna represent it with this little box with an f in. That represents my entire function definition. If I do in my console, now log multiplyBy2, what would I see, James?
[00:03:58]
>> Paul: You would see the actual source code for the function.
>> Will Sentance: Yeah, exactly. I'd see the block of code itself function multiplyBy2. You know I would see the whole thing with the code in my console. That is what we mean when we say declare a function. Sometimes we think or we just sort of go there's a functioning code, none of that.
[00:04:20]
The key word function literally means go save in memory, go save in memory this particular functionality. All right, excellent, what our third line of code that executes, Sean?
>> Sean: It's doing the same thing as our first constant declaration, just creating a piece of memory called name, sending it to a-
[00:04:44]
>> Will Sentance: Excellent, Sean, what was not our third line of code?
>> Sean: const result.
>> Will Sentance: Right, why not?
>> Sean: Because that is not being called yet.
>> Will Sentance: Exactly, we do not go into the body of a function until what, Sean?
>> Sean: Until it's called.
>> Will Sentance: Until it's called, excellent.
[00:05:00]
All right, Sean is spot on there. And folk, this may seem profoundly trivial. Okay, I get how to store stuff in memory. But this foundation is what we need. This level of precision is absolutely vital for everything that follows, all the way up to rebuilding async await with generators.
[00:05:21]
It all in the end depends on these foundations. All right, excellent. So, as soon as we start running our code, we spin up two things. One, the ability to go through our code line by line. That's our thread of execution. Remember, threading its way through and executing the code line by line.
[00:05:39]
And simultaneously we spin up, it's right there, the executing policy is you encode line by line, a live memory of variables with data. A live store of labels with data. Posh name for that is a variable environment, we can call it as a variable environment. Think of it as being, environment is the things around me.
[00:06:00]
These are the variables around me, the variable environment. Now, these two halves together are known. These two halves together, the thread of it, we're gonna walk through. We didn't copy out the lines in the thread, there's no point. But these two halves together are known as an execution context.
[00:06:20]
A context is a space to do something, a space of context in which we do something or it's the space in which we execute our code, it's an execution context. And it's the global one cuz we're gonna discover whenever you wanna run code, including for example, when we wanna execute the code inside a function, we're gonna create a little baby local execution context just for running the code inside a function, we call that the local one, just for the stuff inside the function.
[00:06:51]
So this though is for our overall code, it's called the global execution context. All right people, let's see. What's next? All right, as Sean rightly said, we did not execute, we did not call, we did not invoke multiplyBy2, so we stayed in which execution context, Sean?
>> Sean: Global.
[00:07:14]
>> Will Sentance: Global, excellent, but now we are going to execute a function and see what happens. So we've declared number three, declared multiplyBy2 the function. What is our next line of code? Mr. Henderson.
>> Brian Henderson: Yes.
>> Will Sentance: What is our next line of code, Brian?
>> Brian Henderson: We are creating a new label in memory called output.
[00:07:36]
>> Will Sentance: Excellent, do we know what to assign to it yet?
>> Brian Henderson: It's undefined at this point.
>> Will Sentance: Very good. Because what's the right hand side? Is the right hand side a value that we can store?
>> Brian Henderson: No, it's calling the execution of-
>> Will Sentance: Exactly, it's a command to go and do something.
[00:07:53]
It's actually not a value we can store on the right hand side. Output has zero interest in multiplyBy2. That is a command to go and run some code whatever gets returned out known as the, what Brian? What's the generic name for what gets returned out of function?
>> Brian Henderson: The return value.
[00:08:11]
>> Will Sentance: Return value, exactly. Quite literal, the returned value. That's what's going to be assigned to output. All right, let's do it. So output is going to be the result, the return value of calling multiplyBy2 with the input of 4. There we go, so what did I say we create whenever we have code to execute?
[00:08:38]
Blessing?
>> Blessing: Look at the execution context
>> Will Sentance: An execution context, I'm gonna represent that. This is the bigger box with two parts I'm gonna represent that with a little box with two parts, here it is. I'm taking this slowly cuz these are genuinely, over the next 10, 15 minutes, we're gonna see the three pieces of synchnous JavaScript execution.
[00:08:58]
If we don't get these pieces down, nothing else follows. So into this execution context we go. And just like our global one for running the main code, now we're gonna run the code for just inside multiplyBy2, we're gonna have a little memory just for the code, just for the things that get announced, get declared.
[00:09:18]
The variables, and functions, and parameters, and arguments that get declared inside of multiplyBy2's body. They're just gonna be sorting here. By the way, when this function finishes executing, all those pieces, unless they're returned out, will be deleted automatically, garbage collected. It's stuff that we can't access again, we can't reference those names again, so it's garbage.
[00:09:46]
It's memory that's being wasted. We're gonna automatically clean it out in JavaScript, okay, except in one special condition which we'll see a little bit later on. Cuz it's my favorite thing in JavaScript, those times when all our data is not necessarily deleted when we exit a function, the most beautiful concept in JavaScript.
[00:10:05]
And even though we're not gonna go through it as the focal point, inevitably we have to come to it, in its radius. Okay, good, so in we go. And what is the first thing, Rick, inside our local execution context that we're gonna do?
>> Rick: Defining a constant variable called result.
[00:10:27]
>> Will Sentance: So that's our second thing, Rick. What's the very first thing we put in our local memory?
>> Rick: The function.
>> Will Sentance: Not the function, Michelle?
>> Michelle: The input number.
>> Will Sentance: Exactly, input number which is known as our parameter, remember the placeholder. We defined a function which is to say, we will run this thing later on.
[00:10:47]
When you run me, better make sure you fill in that blank, that placeholder and put number with an argument. Parameter is the placeholder. Argument is the actual value that gets passed in. Michelle, what's our argument?
>> Michelle: Our argument is 4.
>> Will Sentance: Excellent, and so result is 8. And the final line of the body of the function says do what, Josh?
[00:11:08]
>> Josh: To return 8?
>> Will Sentance: To return 8, I like that. Return the value of result, 8. It's not returning result. It returns the value of result, which is a number 8. I don't like saying return result, it kind of implies the whole thing. It's JavaScript sees return result and goes, what's result?
[00:11:24]
8, okay, perfect. Return it out to where? What was your name, dude?
>> Brady: Brady.
>> Will Sentance: Brady, sorry Brady. Brady, to return out to where?
>> Brady: To the label output.
>> Will Sentance: But to which execution context?
>> Brady: To the global.
>> Will Sentance: To the global, exactly. Return out 8 into the global execution context.
[00:11:50]
Where it's stored in output, perfect. Folk, I know this may seem procedural, but I know you can see this and go yeah, yeah, well I get that output is gonna be 8, I got that. But we need to have the precision. So now notice, by the way, that we weren't allowed to move on to the next line in global declaring the output until we'd finished running multiplyBy2 with the input of four.
[00:12:19]
Our thread of execution, the ability to go through the code line by line. When did its way in to the column multiplyBy2, where it spent time going through the code line by line, and then hit what keyword to exit? What keyword, Mike, said to exit?
>> Mike: Return.
>> Will Sentance: Return, and if there's no return statement there, the closing curly brace which implies an implicit return is gonna insert return for us.
[00:12:47]
And out, the return. In other words, JavaScript, how many things can it do at a time? One, its thread is singular. It's not going to continue down in global code while simultaneously running multiplyBy2. It's almost to say, okay, let's keep going down here, and continue in here simultaneously.
[00:13:06]
Uh-uh, one of the beautiful things about JavaScript is it's so predictable because it's always one thing after another in order, top to bottom. At least in its core synchronous nature. We'll see when that doesn't apply of course. So JavaScript is synchronous. In order, top to bottom and single threaded.
[00:13:24]
We can't suddenly do two things at the same time. Excellent, so now we do return out to the global execution context. Where we encounter declaring new output, which is gonna be the return value of another function call to multiplyBy2. We're gonna create an execution context for it. Into it we go, what is the first thing, Rick, in our local memory?
[00:13:51]
>> Rick: The input number.
>> Will Sentance: Which is known as our? Remember the posh name for a placeholder?
>> Rick: Argument?
>> Will Sentance: So that's the argument, that's the?
>> Rick: Parameter.
>> Will Sentance: Parameter. Okay so, Rick, what is our argument? You're right to say our parameter is input number. What's our argument here?
[00:14:07]
>> Rick: 10.
>> Will Sentance: 10, excellent. All right, and then result will be 20. And we return that back out to global. The 20 is returned out to the global constant, newOutput is 20. So our thread winded its way in, and winded its way back out again.
>> Will Sentance: Okay, but there's a final piece to this synchronous JavaScript model.
[00:14:41]
We have our memory posh name, variable environment. We have our thread of execution, the ability to go through the code line by line. These together are known as an execution context. The two things we need to execute code. The context in which we need, the context of things we need to execute code.
[00:15:01]
But we've got a whole bunch of these execution contexts being created, deleted, created. And then, we run another function inside of that one, it's another little mini one being created inside of there. Keeping track of those to us is visually easy. I finished coding multiplyBy2. I come out of it, and I'm back where I was before when I started coding multiplyBy2.
[00:15:23]
We can visually see that very easily. JavaScript doesn't have that same ability to visually see I was previously, I called this function in global and I was in the big box when I moved it to the little box. When I finished from the little box, I go back out to the big box.
[00:15:41]
JavaScript doesn't have that ability. It needs to keep track of where it is in the code right now, where it was before it started being inside this function, where it's gonna go back to when it finishes inside this function. What, this is a knowledge thing, does anyone know what data, we can store that sort of information in any format.
[00:16:00]
But there's a particularly nice structure, way of structuring data that will store that information very cleanly. Anyone know what that structure might be?
>> Michelle: Stack.
>> Will Sentance: It is a stack. Exactly, in fact, it's gonna be a stack of calls. A stack is a, we have arrays. Arrays say, a list of data where I gonna be able to grab an element at any random position.
[00:16:22]
That's not reflecting what we want to do here. Here, we want to say, just like a stack of plates. I put the first one in, I start off in the global execution context, that's my first element in my stack. And then when I start running multiplyBy2, I add it on top.
[00:16:41]
And that's like adding my next plate. If I had to run another function inside of that, I'd add that one on top. When I finish in that one, all I care is that when I take that one away, the previous one that was there before is still there, and that is the essence of a stack.
[00:16:53]
It's that when I take the last thing that was there off, I'm back to where I was before. And so a stack is gonna be a stack of calls to functions. Starting of, here is the call stack, the stack of call to functions. Starting of with the kind of representation of our overall, think about whole code base as a function called global, but as soon as we start running our code we're running global.
[00:17:19]
So starting off with global as soon as we start running our code. When we start running multiplyBy2.
>> Will Sentance: Paul, what would it make sense to do to our call stack?
>> Paul: Add on the new execution context.
>> Will Sentance: Add on the new execution context, exactly. Add on the call to multiplyBy2 with the input of 4.
[00:17:39]
Meaning while I am in my multiplyBy2 function, my thread is in my multiplyBy2 function, multiplyBy2 is gonna be top of my stack of calls. My one simple rule is, whatever's the top of my call stack, that's where I am right now. And then, as soon as I return out, what's gonna happen, Paul, to my call stack?
[00:18:02]
>> Paul: multiplyBy2, that execution context disappears. You go back into the global, and then you-
>> Will Sentance: Excellent, I'm gonna get rid of multiplyBy2 off my call stack. And we may know, therefore return out to global execution context as an output, but JavaScript doesn't. JavaScript knows that because look what's on my call stack now?
[00:18:20]
Don't panic. It's global and back out to global. This allows JavaScript to keep track of where is it in its code, what line is running, and then when I finish in the current execution context, where am I going to return back to? Well it's get rid of where I was, and the next layer down is where I'm returning back to.
[00:18:38]
All right. By the way, posh name for adding to a stack is not to add, is not to throw on, is to what Sean? Victor? What's a posh name to add to a stack, anyone know?
>> Victor: Push.
>> Will Sentance: Push, that's the computer science technical term for adding to a stack.
[00:18:58]
And what's the posh name, Josh, you know, of getting something off of stack?
>> Josh: Pop.
>> Will Sentance: Pop, exactly, push and pop. Excellent, all right, good. Yep, we talked about this. So let's have thumbs on these core foundations. Thumbs is a widely used pedagogical technique to indicate one's understanding.
[00:19:17]
You lost me, I'm very clear, I have a clarification question. Everybody's thumbs out, right now. It's okay to have clarifications. Nobody? Very, very frustrating. All right, good, good.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops