Check out a free preview of the full The Hard Parts of Asynchronous JavaScript course
The "Promises & Microtask Queue" 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:
While illustrating another example of Promises working with JavaScript and Web Browser features, Will introduces the Microtask Queue (or Job Queue). Overseen through the Event Loop, the Microtask Queue is where tasks initiated by promise objects get processed before callback queue.
Transcript from the "Promises & Microtask Queue" Lesson
[00:00:00]
>> Will Sentance: We need to know how our promise deferred functionality displays a promise deferred function, right? Display was deferred on a promise. It wasn't deferred by passing into web browser feature and then pass back into Java. So this is deferred by a promise, how it gets back into JavaScript to be run.
[00:00:22]
Okay so I didn't know any other examples for code in entire history to require three functions to be defined for us to understand it. So I apologise, but this one, this is big. This is like the mega everything coming together in async, it is messy it is big but if we get this down we have every last piece of async down.
[00:00:44]
Okay, we're going to walk through it. It's going to defer functions using an old school callback input. The print hello passes at timeout, old school facade function. It's going to defer functionality using a new school double-pronged facade function, fetch. It's going to block our thread in native JavaScript.
[00:01:03]
It's all gonna come together to ask ourselves which deferred functionality executes first? Okay, here we go, let's wipe this clean. Sean, line one, what are we doing?
>> Sean: Define display as a place in memory.
>> Will Sentance: You got function, functionality, declared in memory. All right, excellent display, thank you.
[00:01:27]
Mike, next?
>> Mike: Print Hello function is defined.
>> Will Sentance: Thank you, Mike. All right, next, Michelle?
>> Michelle: We define a function that in a black box manner-
>> Will Sentance: Nicely put, exactly in a black box manner. Block for 300 milliseconds. We don't how it's gonna do it can you remind us just how it might?
[00:01:57]
How might we block our main JavaScript thread from running any further code for 300 milliseconds?
>> Michelle: Make a really nasty forward loop.
>> Will Sentance: Yeah, we long loop, exactly, which may be assigning stuff, whatever, it's going to take time. Excellent, thank you, Michelle. Now, we hit the interesting stuff.
[00:02:14]
We've done our setup. Now we hit things that we get interesting. Okay, do you have enough room here? [SOUND] Yeah, probably, okay. Set timeout is past the entire print hello function definition. And it's additional argument, Michelle, is?
>> Michelle: Zero.
>> Will Sentance: Which represents?
>> Michelle: Zero milliseconds.
>> Will Sentance: Right, zero milliseconds after which we want print hello to call.
[00:02:52]
Now, we probably realize all that could mean is that's the minimum. We know it will not be called before then. But when it's allowed It is the amount of time a background web browser timer will run for, that's what we know it does. It does not tell us in JavaScript how long until that function will be called.
[00:03:13]
All we know is that zero milliseconds will pass before that function Print Hello is ever allowed back in the JavaScript. But it could be a quite a lot longer before it's allowed back in, but it'll be queued up ready to go after zero milliseconds. It'll be sitting there waiting to be on the call stack after zero milliseconds.
[00:03:28]
Okay, so what does settimeout do on that note? Nothing in JavaScript, but what does it do, Blessing, in the web browser?
>> Blessing: Its calls are fetch [CROSSTALK] Sorry [LAUGH] web browser feature timer.
>> Will Sentance: Timer, excellent. With the properties
>> Blessing: Of the function to call on completion and the time before it closes.
[00:03:56]
>> Will Sentance: Excellent, and then here is our timer being set up in the web browser with zero milliseconds Is it at this moment, Blessing, is it complete?
>> Blessing: No.
>> Will Sentance: Is it complete? It's zero millisecond timer.
>> Blessing: Yes, yes, it is.
>> Will Sentance: So it's complete already, excellent. And on completion, what did we say we want to do, Blessing?
[00:04:18]
>> Blessing: Once you put the print hello function in the call back queue.
>> Will Sentance: Very, very good precision there by Blessing. We want to add print hello function to the call back queue. So let's do that, let's put the call back
>> Will Sentance: Queue, call back
>> Will Sentance: Queue, there it is, and actually, print hello is ready to go in there right now.
[00:04:49]
It's ready to go and be added. So your event loop is going to be checking already can I add this stuff back to the cool stack. Can I add this print hello function back to the call. It's sitting there, ready,
>> Will Sentance: To be run from basically, let's say this was one millisecond, basically from one millisecond.
[00:05:17]
>> Will Sentance: At one millisecond. It's sitting there basically from one millisecond In the call back queue, ready to be executed. It's complete, it's ready, it's [SOUND] past it's ready to go back to the event loop. We're going back to go to the call stack, but the event loop is sitting there, and it's like a god protecting.
[00:05:40]
>> multiple: [LAUGH]
>> Will Sentance: So what is our next line of code? Because print hello is ready to run, can it run though? No, cuz what's my one simple rule for the event loop? Michelle?
>> Michelle: The call stack has to be clear
>> Will Sentance: Has to be totally clear and all global code has to finish executing, so we are definitely not there yet.
[00:05:57]
So instead at two milliseconds we hit what line, Michelle? Actually Abdi, what line we hit at two milliseconds?
>> Abdi: Variable constant.
>> Will Sentance: Excellent, be careful saying variable, I think from now on, just say a constant future data, that makes sense, or a const, yep, future data. Now it's gonna start off undefined, as anything that's right hand side is unfinished work, starts off undefined.
[00:06:22]
It's gonna go and figure out what that right hand side is going to evaluate to. Evaluate is the posh word for get me down to my value. This is a command, I can't store a command. I can't store a command to go and run a function. I can only store the returned value from that function.
[00:06:40]
Okay, so let's start doing that. Future data is going to be the return value in JavaScript using this double prong façade function fetch that does something in JavaScript. And also in the web browser features themselves. But it does do something in JavaScript as well, this time. And what is the thing that it does in JavaScript, Abdi?.
[00:07:10]
>> Abdi: I create an object with value and fulfillment.
>> Will Sentance: Excellent, yeah. It returns out an object with a property value that's undefined. On fulfillment that's an empty array into which we wanna push all functions that would also triggered when value gets updated. And this returned out JavaScript object is the output of running fetch.
[00:07:37]
This is what comes out, it's returned and therefore is assigned the future data. Okay, so there's future data is now that returned out promise object.
>> Will Sentance: There it is with value.
>> Will Sentance: And we're almost there, people on fulfilment
>> Will Sentance: Is an empty array that will be triggered to run all its functions.
[00:08:01]
When value gets updated by fetches where browser works, so let's talk about it where browser work, what is the consequence? All right, who am I gonna call on? Victor, what is fetches in its facade function form? What's a thing it does in the web browser in addition to this objective it returns out in JavaScript, but what's it set up in the web browser fetch?
[00:08:26]
>> Victor: An XHR.
>> Will Sentance: It sets up an XHR request or XMLHttpRequest. Exactly, it's going to get going this web browser feature XHR, so let's add it, let's add it below here, it's the next one, XHR. What properties does it need, Brian?
>> Brian: It's the URL, the path, and the method.
[00:08:55]
>> Will Sentance: Yeah, [INAUDIBLE] yeah, the URL, the path, and the method. And it also defaults to get, everything in blue is the web browser, that's gonna send off to Twitter and their service, an http request. And we've gonna hopefully get some data back. Is it complete, Brian, at 2 milliseconds?
[00:09:26]
>> Brian: No.
>> Will Sentance: Definitely not. But on completion, what do we want it to do, Brian do you what we want it to do on completion?
>> Brian: We want to assign the value of the data that we got back to value.
>> Will Sentance: Excellent, on what object?
>> Brian: Future data.
[00:09:44]
>> Will Sentance: Very well put, Brian, futureData.value will be whatever comes back from this background work, well done, Brian. So fetch's work is done, fetch is the most complex, one word API I've ever seen. It's literally two-pronged, it does something in JavaScript, something in the web browser, that is why it's ridiculous.
[00:10:08]
Okay, but now we continue on in JavaScript to immediately after we dump future data equals return value of fetch which was object, future data, promise object. What's the next line of code we hit, Mike?
>> Mike: The futureData.then line.
>> Will Sentance: Excellent futuredata.then parsing the display, the entire definition. I always draw that little box here to show it's the entire definition of display being parsed to the then.
[00:10:35]
Which we're actually gonna replace the then method with store this function on this object data future data to be triggered when value is outdated. That's what then is doing, let's imagine it's called that. It is being done right now, it's only job is never [INAUDIBLE] do anything again, it's only has one other job.
[00:10:56]
But it's only interesting job for us right now is getting that function stored on futureData. Under it's, what array, Ben?
>> Ben: Unfulfillment.
>> Will Sentance: Right, it's hidden unfulfillment array, that's where it's gonna be stored cuz it's hidden unfulfillment array. And so we are going to put the display function, or at least a reference to it, a link to it in the unfulfillment array, there it is.
[00:11:22]
Okay, good, by the way, all through this printHello is still sitting there saying, can I come back on the call back queue? Callback's called whatever it's called, call sack, whatever that thing's called, precision. Back on the call sack and event loop is going, you're not allowed back on yet but maybe now it's allowed back on cuz we don't have no.
[00:11:42]
What's actually our next line of code, Abdi?
>> Abdi: Console log in meFirst.
>> Will Sentance: We've got one before that, dude just after the then.
>> Abdi: I didn't see that, we're running the function of block for at 300 milliseconds.
>> Will Sentance: Block for 300 milliseconds, who's functionality we don't know how it's working, we just know that it's gonna sit on our call stack.
[00:12:03]
We're gonna enter it, we're gonna sit there for 300 milliseconds and come back out only at 303 milliseconds. Okay, while it was on the call stack, let's put it on the call stack so it's really clear. While it's on the call stack, block for 300 milliseconds, while it's on the call stack, what happens?
[00:12:29]
Well, actually, our request comes back, so it's something like, let's say, 290 milliseconds. Our request comes back and then what's our very nicely structured data we get back?
>> Ben: Response-
>> Will Sentance: Right, exactly, hi, we're gonna simplify here slightly, there it is, hi, and what at that point is it going to trigger to update?
[00:12:56]
>> Ben: Future data.value.
>> Will Sentance: Excellent, there it is, which is going to trigger this little guy here, display function, it's ready to go. So at this point, while we're inside our block for [INAUDIBLE] call stack, we have ready to go printHello, we've known that for a long time. We now have ready to go, display, so we don't call display, where do we think we parse display, Ben?
[00:13:26]
>> Will Sentance: Michelle, we're not gonna call display immediately, where's it gonna go?
>> Michelle: You can stick it on the callback queue.
>> Will Sentance: We're gonna put it on the callback queue.
>> Will Sentance: Or are we? Yeah, there it is, for now, they're at good display on the callback queue. Sounds good to me, and it gets added there at about 290 milliseconds.
[00:13:45]
>> Will Sentance: The people who stop watching the video right now, they're getting falsehoods but there we go, there it is, nicely on the callback queue, hurray, excellent! Block for one second finishes running, so for 300 milliseconds finishes running we come back out of it at 303 milliseconds. And we have teed up to go, display, actually I can't do this, we have teed up to go, display, we have teed up to go, printHello.
[00:14:15]
We have teed up to go, what's our next synchronous line of code, Brian?
>> Brian: meFirst-
>> Will Sentance: Which one's gonna go first? Okay, I think the first one we know, which one's gonna go first, which one's gonna go first?
>> multiple: meFirst.
>> Will Sentance: meFirst, yeah, we got that bit, synchronous code is the monarch, no, that's not, that doesn't make any sense, I don't like that, I don't like that sort of stuff.
[00:14:37]
Someone asked me during a talk on Sunday or Saturday why you don't talk about the royal wedding?
>> multiple: [LAUGH]
>> Will Sentance: I left this country for reason,
>> multiple: [LAUGH]
>> Will Sentance: Although I did go and watch the pictures, I'd sneakily watch the pictures and pretend it didn't affect my sense of views in meritocracy.
[00:14:58]
All right, so me first at about 303 milliseconds, we get me first. So let's just first note, by the way, that we deferred printHello at one millisecond and for 0 milliseconds, and it still has not been allowed to run. We then deferred,
>> Will Sentance: Display function to be run, triggered to be run, what I did came back.
[00:15:30]
And even though it's been ready to go for ten milliseconds at this point, it's still not allowed to run. When we exit block for 30 milliseconds, we still hit the console log first, the synchronous code first, we knew that there. Now is where it gets really interesting, now is where it gets really interesting, we have two event loop, at least now it's happy.
[00:15:51]
All the global code has finished running, now it's ready to start running stuff in the queue.
>> Will Sentance: We have printHello ready to go, it's been in the queue for a long time And we have display ready to go. It just end of the ten minutes ago. It's good to go now.
[00:16:09]
It took me a little bit of time to go back, but now it's good to go. Which one is gonna go first? Well, we've already said, it's in the queue. How do queues work? Alec?
>> Alex: Yeah, you gonna buy stocks.
>> Will Sentance: Yeah, you gotta add display in the back of it, right?
[00:16:22]
No [LAUGH] not stocks [LAUGH]
>> multiple: [LAUGH]
>> Will Sentance: Very good, very funny.
>> multiple: [LAUGH]
>> Will Sentance: Very good. It's gonna be added to the end of the queue, so it would be the last thing. It's the last thing added to the last thing out.
>> Alex: First in, first out.
>> Will Sentance: First in, first out.
[00:16:36]
So, who thinks next line is print hello? Raise your hand high if it's print hello. I know I'm doing my, is not the right answer voice.
>> multiple: [LAUGH]
>> Will Sentance: But come on, give me another explanation why. But you're right, well no the three of you raised your hands are wrong but thank you, because everyone thinks of that but they know they heard the voice.
[00:16:56]
>> multiple: [LAUGH]
>> Will Sentance: It's the wrong answer voice. And so they refused to, they didn't wanna get the wrong answer. Embrace it. Okay, turns out JavaScript has an additional queue. It has an additional queue. People don't talk about this queue. People aren't talking about this queue. People should be talking about this queue.
[00:17:17]
This queue is an additional queue. It's called, the micro. Task and the actual JavaScript spec itself calls it the job queue. The microtask queue where any functions that weren't deferred using these traditional model, where I set up a web browser task and use web browser feature timer for example, and don't return anything into JavaScript no object that function gets treated directly from the web browser feature completion.
[00:17:51]
It gets pushed to the callback queue. But, I now have a new way of teeing up background work. These new types of web browser feature APIs or facade functions. Well, it's like fetch. They return out an object, a promise object, into JavaScript. Their value gets updated from the background web browser feature.
[00:18:18]
And it triggers in JavaScript the function display. And that triggered function is not ending up on the callback queue. It's getting passed to the micro task queue, display passed to the micro task queue. At yeah, 290 milliseconds, fine. Much later, but the event loop prioritizes tasks in the micro task queue.
[00:18:49]
And so what happens here, yes, now we finished our console log, the event loop goes hooray, the call stack's empty, global code execution is finished, I'm gonna go and check not my call back queue first, but my micro task queue. What do I find there? The recently added display function.
[00:19:06]
What I do with it, I put it on the top of my codes tag with it all human being the value that triggered it to run, and so into my display function goes my argument, high. And so, add about 304 milliseconds. I'm gonna finally call, or not finally.
[00:19:30]
Fairly, quickly call display with high and that's gonna do what in my console, Michelle? What display input gets what? So, display is parameter.
>> Michelle: Yeah, it takes in the data, but [CROSSTALK] Future, data, value.
>> Will Sentance: And that's gonna then be? Which is?
>> Michelle: Which is how high.
>> Will Sentance: High.
[00:19:52]
>> Michelle: And then it console logs that out.
>> Will Sentance: Be really clear, it takes in the futureData.value, which is high, because that futureData.value is triggered by this background work. Which then triggered the display function to run, with that value as its argument, very good. And then there it is at 304 milliseconds.
[00:20:10]
We are gonna console log pi. Then I forgot to say we therefore DQ'd this task when we took it to the call stack. We've now finished it on the call stack. The event loop's doing spinning, it's saying a cause empty, it's empty again. Microsoft's queue, it's empty. Call back queue, got something in it.
[00:20:35]
Finally, our poor little print hello.
>> multiple: [LAUGH]
>> Will Sentance: That's been delayed for so long, this little guy's been sitting there since one millisecond. Finally, poor [INAUDIBLE] At 305 milliseconds is allowed onto the call stack. And three it is, print hello. Out of the call stack at 305 milliseconds, we get,
[00:21:03]
>> Will Sentance: Hello. Despite it being the first thing to be teed up, the first thing to be kicked off to be deferred. Before we deferred our display functionality. We could display our tweet when it came back. Before we [INAUDIBLE] First, it would not allow back onto the call stack.
[00:21:24]
>> Will Sentance: DQ from the callback queue now. Wasn't allowed back onto the call stack or allowed into the call stack until all synchronous code is finished running, and until it's cleared our microtask queue as well. This folk is all of asynchronous JavaScript, every last piece.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops