Lesson Description
The "Microtask Queue Q&A" Lesson is part of the full, JavaScript: The Hard Parts, v3 course featured in this preview video. Here's what you'd learn in this lesson:
Will answer questions related to the microtask queue and introduces the ability to abort fetch requests using an abort signal with a timeout, which cancels the request if it takes too long, triggering error handling instead of success. This control over asynchronous tasks enables building fast, non-blocking web applications with a single JavaScript thread managing background work efficiently.
Transcript from the "Microtask Queue Q&A" Lesson
[00:00:00]
>> Will Sentance: I do want to just add one, well, summary of this, but also add one more thing as a bonus. So promises, what are our problems with these? Well, most developers do not know how they're working under the hood. Without a shadow of a doubt, most people think that there's some sort of running of that function display at the moment when it's passed to then. Instead, much as before, we set up background work with fetch, we store an object in JavaScript that is associated with that background work, to which we can then attach a function that will only run when that background work completes and that function is then populated, its input, its argument is populated with the associated data that we retrieved.
[00:00:47]
So therefore, debugging becomes super hard with these promise objects, and developers fail technical interviews, how about that? That's setting up the problem. Our benefits of the promise style, cleaner, readable code that has a pseudo-synchronous style. Rather than as before with our setTimeout where we pass in a function definition that we know is going to run away later. Here, by the way, we're still passing in a function definition that we know is going to run away later, but at least we're passing it in after the word then.
[00:01:19]
I don't know. And it has a really nice error handling process. Suppose instead of getting back cute puppy, we instead got back some error. Maybe we have some error, we didn't get a response from the server, maybe instead we had some error saying you're not allowed access to this adorable video. Our promise style very helpfully gives us a tool to handle that error, and that is an additional array on our future data promise object, reject reactions.
[00:02:00]
Reject reactions. Also hidden is another array into which we can attach functions we want to have run on an error being returned and assigned to this result property. If we instead get an error here, it will automatically not run the fulfilled array, but the rejected. And the functions in there, we can then write, such as to handle the error. How do we attach the functions to that array? Does anybody know we don't use dot then?
[00:02:33]
Does anybody know what we attach? Yes, Michael? Catch, catch, exactly. Rather than dot then we would run .catch and pass in our function to have run automatically with our error. And there's one more thing I do want to add, oh, I don't, I probably shouldn't put this, let's have a look. We have rules for the execution of our, oh yeah, yeah, we go, we have rules for the execution of our asynchronous code.
[00:02:58]
Hold our promise deferred functions, we've said this all right, in the microtask queue and callback functions, the ones passed to old school stuff like setTimeout in the callback queue. When the web browser API finishes, they go into those queues. Only add the function to the call stack, i.e., run it, when the call stack is empty, all global code is run. Have the event loop be checking that all the time.
[00:03:22]
Prioritize functions in the microtask queue over the callback queue. Before we get to our summary, I want to add one more thing that I will try and keep tight, but it's just a fun new thing that was added two years after fetch was introduced. Which I do think is quite entertaining, and that was the ability to abort a fetch background task when we have some information, a timeout, something that determines we don't want to keep it going.
[00:03:51]
We don't want to wait for a response because the server may never give us a response, but instead abort it. And that is using this abort signal approach. It allows us to pass in, and I'm going to try and keep this fairly tight, I want to show here that we can pass in as a second input an object, now this object could also have the property of whether we're going to be getting or posting or otherwise, but we're just going to use its property signal that, to which we are going to attach, and let's declare, the only line we've added here that was added in, oh wow, actually this bit, the abort signal timeout was added in 2022.
[00:04:36]
The ability to abort to pause background work was added in 2017, but this particular one, that's a timeout-based signal, was added in 2022. So, let's squeeze this code in here, we're going to declare signal, and it is going to be the result of calling this built-in feature abort signal, built-in, we're not, we didn't define that ourselves, built-in, calling the timeout method on it, and it is going to actually also act as two-pronged.
[00:05:10]
Within JavaScript, it's going to return an object that has on it the property aborted, and it has on it the property reason. And these actually aren't hidden properties, these are properties we can see, and the aborted is additionally false and the reason is initially undefined. OK. This object we can pass in to our fetch, when we first set up our background work speaking into the internet and our promise object.
[00:05:45]
We can pass it in there. We don't need to show the details, but we can pass in that signal object that we just defined here. It is going to modify the behavior of our network request. As soon as we defined that signal, it had two consequences. One, it created an object in JavaScript, and two, it set up in the background. What do you think? It's a countdown, what do you think it set up, Chris? Timer.
[00:06:22]
A timer, exactly. A timer in the background. For how long, Chris? 200 milliseconds. I don't think we're going to, well, when do we set this up, one millisecond. So at one millisecond that timer was obviously not complete. Jeez, I'm trying not to go too detailed on this, but obviously not complete, but immediately after we passed in the object that was connected to that timer to fetch, and you know what, you know what I did?
[00:06:57]
It set up a bond in that network request in the background, in the web browser to that timer. Such that if that timer completes, ensure that we abort, we cancel the background network work and instead return an error. And as it happens, we saw that at 270 milliseconds we got our response, but if we'd had this background timer passed in with the abort signal, with the 200 milliseconds timer, well, I would say then at 201 milliseconds, it would have completed.
[00:07:35]
And what would that have done to our network request, our background work? It would have said, I don't know which color to use here. Oh, orange for error. It would have said error, not cute puppy, we would have never reached our cute puppy response, and our error would have been passed in to our result, and we would have had error here instead, meaning would we have called our fulfilled array functions?
[00:08:02]
Nope. Exactly, Michael, we'd have jumped straight to our reject ones, where you can see I wrote .catch to add to the reject one, actually, just the same display function, probably should have written an error handling function, but to be fair, displayed our error, known as a timeout error. And our aborted property here would have been transformed to true, it was aborted, and the reason being a timeout error.
[00:08:29]
But people, this is just a bonus thing to see the control we have, and then once we have our mental model, we can see where this activity is happening and the control we have now over our background work with the all powerful fetch. We can even set on fetch a connection between one background task, speaking to the internet, and another one, a timer, and set that if that timer is completed before the background speaking of the internet completes, then return from that background network request into the promise object, an error, not instead our response, cute puppy.
[00:09:08]
So people, promises, web APIs, callback, microtask queue, and the event loop all enable us to build non-blocking applications. We were able to plow straight on from these two rather demanding background tasks, well, not this 10 milliseconds, but it could have been 1,000. Our call to fetch are all happening, or sorry, our call to fetch, which triggers a network response, a network, the timer, any stuff that could take time, even short time, because it could have been longer, happens in the background.
[00:09:37]
It means we don't have to wait in our single JavaScript thread and don't block code, further code from running. We set up our background timer, we set up our speak to the internet, and yet we could then still hit our block for 300 milliseconds, we could still hit our console log, me first. However long it takes, because we can't predict when our background work will complete. Much of it, not a timer of course, but much of it, like speaking to the internet, we don't know when it's going to come back.
[00:10:09]
So we let JavaScript handle automatically the running of the function on completion. We do not say wait in here until you get the data back, we don't know how long it could be, then run it. Nor do we say where, nor do we try and time it. Put the parens on at the moment when the data comes back, rely on JavaScript to automatically add our parens, add our parens, and insert the data that came back automatically for us.
[00:10:37]
We didn't, I didn't see parens anywhere here on display. I didn't see parens anywhere here on print hello. Instead we passed them into these facade functions and relied that when they came back into JavaScript, JavaScript added parens for us. And even in the case of display, inserted the data that came back automatically. This allows us people to build the modern web applications we are so experienced with.
[00:11:06]
The asynchronous JavaScript nature of the nature of JavaScript being asynchronous is the backbone of the modern web and lets us build these fast, non-blocking applications. What we know as single thread is in fact a single thread in JavaScript and a whole bunch of background work behind the scenes.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops