Check out a free preview of the full The Hard Parts of Asynchronous JavaScript course
The "Calling the Outside World" 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:
Will shows how code designated for deferred functionality is only allowed back into JavaScript when certain conditions are checked by the Event Loop: If the Callback Queue contains code, that code is can enter the Call Stack only when the Call Stack itself is empty and the global execution context has run all of its code.
Transcript from the "Calling the Outside World" Lesson
[00:00:00]
>> Will Sentance: Line one, James, what are we doing?
>> James: You are declaring a function called PrintHello
>> Will Sentance: Excellent, good job from James. Line two, who have I not called? I called on almost every person now.
>> Will Sentance: I've called on every single person, Mike, line two, what are we doing?
[00:00:16]
>> Mike: The function block for one sec is declared.
>> Will Sentance: Block for one sec. And for we're not specifying how it works necessarily, but this function, when it's called, is gonna sit on the call stack for 1,000 milliseconds. This is not a function that's sending work off the background.
[00:00:36]
It's gonna sit there for 1,000 milliseconds. Sonia can you think of a way in which I could write that functions such that I did that? What could I do that would take a 1,000 milliseconds? It's gotta be in the que of jobs threads, it's gonna be doing something very very fast.
[00:00:50]
Mini-tasks, very very fast. Ben, what can you think of?
>> Ben: Looping.
>> Will Sentance: Looping, exactly looping will do that. Lots of little processing steps very, very fast. It's gonna be a big loop to last 1000 milliseconds in a modern JavaScript engine. Big old loop. But there is a loop long enough that would last 1000 milliseconds.
[00:01:06]
You're not doing it outside of JavaScript. It's very much pure JavaScript. And therefore is blocking us continuing in our code when that function is called for 1000 milliseconds. Excellent. Now, now Mike, we are gonna call setTimeout with the argument, the print hello function definition we're definitely not calling it and the argument 0.
[00:01:32]
So Mike try to talk me through what's going to happen here, and it's going to be in terms of our web browser features isn't it. So what's going to happen here Mike?
>> Mike: I'm not sure. I just know it's not.
>> Will Sentance: So what is setTimeout been set up.
[00:01:47]
>> Ben: It's going to set up a local execution context.
>> Will Sentance: Is it?
>> Ben: No, it's going to call a facade function.
>> Will Sentance: Ha. SetTimeout does, what does it do anything in JavaScript?
>> Ben: No.
>> Will Sentance: It does nothing in JavaScript. Instead, it is going to, it's a label, it's a facade function for a web browser feature.
[00:02:07]
Which feature, Ben?
>> Ben: Timer.
>> Will Sentance: Timer, so it's going to spin up a web browser feature, the feature timer. And it's going to take in the two important things it needs to know. And in the web browser, how many milliseconds, Mike, is this timer going to be running for?
[00:02:34]
>> Mike: Zero.
>> Will Sentance: Zero milliseconds and so at say one millisecond, which is when we're kicking this off, is this timer complete? Mike? It's instantly complete. Exactly. And on completion, what do we want to do? We want to call print hello. We want to pass it back into JavaScript or refer to it in JavaScript and kick it off running in JavaScript.
[00:03:09]
>> Will Sentance: So print hello is immediately ready to run, so do we add it straight to the call stack?
>> off screen: No.
>> Will Sentance: Why not?
>> off screen: It's blocking.
>> Will Sentance: No. But it's here ready. It's ready to go back on.
>> off screen: Because you're not in the JavaScript context or in browser's world.
[00:03:25]
>> Will Sentance: But we are. We're back in JavaScript context. Look. Next line is two milliseconds. Why can't this guy look come back. We said whenever it's ready come back on the call stack. Yeah, you're right though. The next line of code we're going to hit at 2 milliseconds is block 41 sec.
[00:03:44]
We're not sure how it's going to work but we do know when we go into it, we're going to spend how many milliseconds inside of it, Josh?
>> Josh: Milliseconds? 1000.
>> Will Sentance: 1000, good. Well done to Josh, by the way, for his good second to millisecond adjustments. Exactly, plus 1000 milliseconds.
[00:04:02]
That's going to sit on our call stack, so we had global on the bottom, block for one sec
>> Will Sentance: Is gonna sit on our call stack for 1000 milliseconds. Maybe during it, print hello is ready to go. Maybe during it, it jumps on top and starts running. Does it do that?
[00:04:24]
That would be a terrible language.
>> [LAUGH]
>> Will Sentance: Maybe possible. I mean it's certainly possible. But that would be very arbitrary, very arbitrary for when our code would execute. So it definitely can't do, as Michelle said, it definitely can't pass print hello back onto the call stack during another function execution.
[00:04:46]
That looks pretty clear. It kind of sort of random arbitrary. But maybe once that function's finished executing, yeah, once that function's finished executing and we get block for one sec off the call stack and we return our thread back out at an 1002 milliseconds, maybe now print hello is allowed back on the call stack.
[00:05:07]
Who thinks it's allowed back on the call stack? I'm doing my the answer's no voice. Who thinks it's allowed back on the call stack?
>> Alec: Maybe.
>> Will Sentance: Yeah, Alec, maybe,
>> [LAUGH]
>> Will Sentance: Unfortunately, no. Even though poor little print hello, it's been sitting there. I'm ready to run, run me, been ready to run for, at this point, 1,001 milliseconds from when it was first kicked off.
[00:05:31]
The timer was kicked off, it was instantly complete, print hello was instantly ready to come back on, but it wasn't allowed back on. We'll see the exact rule why, actually we're gonna hit next console log. Me, good old me first. If it ever says me first you know it's gonna console log it first.
[00:05:51]
There it is, me first. At 1002 milliseconds.
>> Will Sentance: Okay. Now do we think at this point as we've finished all of our global code, do we think now print hello is allowed back on? Print Hello is now allowed back on. But how does it get back on? It turns out that we need two more pieces to our puzzle.
[00:06:22]
We need a fundamental rule. Our fundamental rule for when deferred functionality. Now yes, it was only deferred by zero milliseconds. But it was still thrown out of JavaScript and associated with a web browser. It was thrown out of JavaScript. We need a rule for when that thing that's been thrown out of JavaScript is allowed back into JavaScript.
[00:06:43]
And we have one simple rule, I must have finished emptying my call stack of any functionality to be run, and finish running all my global synchronous code, all my codes. I could have 1000 console logs. Kind of crazy. I could have spun up this differed functionality inside a function call, come out of it.
[00:07:05]
Have 1000 calls, I could have a while loop that's infinite with console logs in. And I'll never allow print hello back on the call stack. It's never allowed back in. Why? Because when I finish my background features work, print hello does not go straight to the call stack.
[00:07:23]
As Brian was hinting, it goes to something called a queue. It gets queued up as a callback I guess. This has a few names, the task queue. Can we even call it the macro task queue at the moment? But the call back queue is a queue of functions that are ready to come on the call stack.
[00:07:47]
There it is print hello, Blessing, approximately what millisecond was print hello added to the call back queue?
>> Blessing: One millisecond.
>> Will Sentance: At approximately one millisecond exactly, there it is one millisecond and then we have our rule. When is this function allowed back into JavaScript? It's allowed back into JavaScript only when the call stack is empty and all our global code is finished running.
[00:08:15]
And that rule, or the checking of that rule, has a posh name. It's a little sort of process, it's a metaphorical process. The whole process is looping, and checking really fast. Is the course AMD? Is all the global code finished running? Has the queue got anything in it?
[00:08:29]
Is the course AMD? Queue has anything? And that is known as the event loop. It's job is to say is the course AMD finished running all it's stuff? Is the global code finished executing? Is something in the core? Yes there is! This was not empty for a long time, at this point event loop's going no, no, no, we can't add anything on to the call stack because it's got blocked for one second.
[00:08:51]
But even then, console log's sitting there that needs to be run. It's ready to be run in the global execution context. Ha, at this moment the event goes is the courser empty? Yes it is. The callback here has something in it so print hello, you arefinally 1001 milliseconds after you were deferred for 0 milliseconds, you are finally allowed back onto the call stack at 1003 milliseconds.
[00:09:21]
And note these timings are ordinal. They're not, they're ordinal, besides the cardinal ones, okay.
>> Will Sentance: Ordinal meaning it's about the ordering of them, at 1003 milliseconds. Finally, print hello is allowed back on our call stack, at 1003 milliseconds, we print hello there it is people. A beautiful process of deferring our functionality, to then only be allowed back into JavaScript under a certain condition, that condition is checked for by this event loop that's checking it looping very fast that is metaphorical but it is looping very fast to check this condition.
[00:10:03]
Is the callback que, does it have something in it? It does allow it back on when our call stack is entirely empty and our global execution context has finished running all of it's code. And that's it. These six parts are the core of our asynchronous model of JavaScript.
[00:10:23]
Solution three is gonna show us that JavaScript recently introduced two new additional parts to this model. We're gonna see them in solution three. But for now, thumbs on this core six parts, memory, thread of execution, call stack representing our execution context, our web browser features, our callback queue where when our web browser feature finishes its work is where our function is going to be sent.
[00:10:49]
That was deferred by our facade function that spun up that web browser feature timer. And finally, our event loop that checks that callback queue. It says is something in there? Is our call stack good and empty with no global code to run? And says okay, you're allowed back on.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops