Shadowing Practice: JavaScript Visualized - Event Loop, Web APIs, (Micro)task Queue - Learn English Speaking with Video

Creating lesson...
1
The event loop is a pretty notorious topic in JavaScript, but when we zoom out, it's just a tiny component within the JavaScript runtime.
2
We also have the call stack, we have web APIs, we have the task queue, microtask queue, and then eventually the event loop.
3
Well, to be a little more technically accurate here, we actually have the JavaScript engine in which we have the call stack and then also the memory heap.
4
But to keep my slides a little organized, I'll just be showing the call stack here.
5
All these components together allow us to use asynchronous tasks in a non-blocking way in JavaScript.
6
And this is important because JavaScript itself is single-threaded.
7
We're only working with a single call stack.
8
So the call stack manages the execution of our program.
9
So if we have the following script, we first have console.log1.
10
So a new execution context is created, pushed onto the call stack, which is then evaluated and logs 1.
11
Then we have console.log2, same story.
12
Execution context is created, pushed onto the call stack, is evaluated and logs 2.
13
Then on line 14, we invoke another function, the log3 and 4.
14
And within this function body, we invoke yet another function, log3.
15
And within log3, we invoke another function, the console log3.
16
Eventually, it logs 3.
17
Then on the second line, within the log3 and 4 function body, we console log4.
18
4 gets logged.
19
And now the log3 and 4 execution context is popped off the call stack as well.
20
Now, something important to remember here again is that JavaScript can handle a single task at a time.
21
So if we, for example, had this long running task in which we have a pretty heavy computation, it takes a while before JavaScript can continue with the rest of our program.
22
So the console log long task done is only logged after a couple seconds.
23
And this is not what we want because in the meantime, our entire program is frozen.
24
So we want to avoid these long running tasks.
25
But in a real life application, we often have to use these long running tasks, like maybe a network request or anything based on user input, timers.
26
So what happens then?
27
Like, is our entire call stack just blocked until we get the data back?
28
No, because we're actually using web APIs in those cases.
29
And web APIs provide a set of interfaces that allow us to interact with the browser's features.
30
This includes functionality that we often use, like the document object model, fetch, set timeout, and so many more.
31
The browser is a very powerful platform with a lot of features.
32
Some of these features are required like the rendering engine
33
or the networking stack
34
but we also have access to some cooler ones like device ones sensors cameras geolocation
35
and so on okay cool
36
but what does this have to do with long running tasks
37
well some of these web apis allow us to offload long running tasks to the browser
38
so when we invoke such an api we're kind of just initiating
39
that offloading and web apis that expose these asynchronous capabilities are either callback based or promise based.
40
So first let's focus on the callback based APIs and I'm just going to use the geolocation API because it's fun.
41
I could have used any other callback based API, but let's say that we want to get the user's location.
42
And for this, we can use the get current position method exposed by the geolocation API.
43
And this receives two callbacks.
44
First, we have the success callback in case everything goes well
45
and the user allows us to get the location and we actually get it from the browser, or the error callback in case anything goes wrong.
46
So let's see what happens when we actually use this in our script.
47
So first, the getCurrentPosition invocation gets added to the call stack.
48
However, this is just to register those callbacks and initiate that async task.
49
After doing that, it can get popped off the call stack immediately, so it doesn't wait for any data.
50
Now in the background, the browser starts some kind of process that eventually shows the user pop-up.
51
Now of course we don't know
52
when the user is going to interact with this pop-up
53
but that's not a problem because this is not happening on the call stack
54
so our entire website is still responsive in case other tasks need to run instead.
55
Now finally the user clicks on allow.
56
So the API receives the data from the browser and uses the success callback to handle this result.
57
However it can't just push that callback back onto the call stack.
58
This could disrupts an already running task can just create very unpredictable behavior.
59
So instead, the callback gets pushed to the task queue, which is also called the callback queue for this exact reason.
60
The task queue holds web API callbacks
61
and event handlers to be able to get executed at some point later in the future.
62
And this is where we finally get to the event loop.
63
It's the event loop's responsibility to check if the call stack is empty.
64
And if that's the case, so if nothing is running, it then gets the first available task from the task queue and moves this to the call stack where it's executed.
65
So now finally we handle the results and the user's location is logged to the console.
66
Another very popular callback-based web API is setTimeout.
67
And setTimeout also receives a callback and a delay.
68
So let's see how that works.
69
So first we encounter a setTimeout and this again gets added to the call stack
70
but all it does again is register that callback and also the delay with the timers API.
71
And in the background the browser will actually handle that timer.
72
Then we have another set timeout and again It registers the callback
73
and the delay now our timers are still running
74
and we have a console log end of script This just gets added to the call stack
75
and logs end of script nothing asynchronous here now after a hundred milliseconds The browser's like hey a hundred milliseconds expired.
76
So now the callback moves on to the task queue There's nothing on the call stack right now
77
So this moves on to the call stack where eventually it logs hundred milliseconds
78
now 2 000 milliseconds are up again same story the callback
79
is pushed onto the task queue call stack is empty
80
so it moves onto the call stack where it locks 2 000 milliseconds
81
so it's just very important to remember that
82
when you have a set timeout
83
and a delay it's not the delay until it gets moved
84
onto the call stack no it's the delay until it gets moved to the task queue
85
so this means that the delay
86
that we specify might not actually be the delay to execution
87
because if call stack was still very full with other tasks
88
and this could run for many more seconds the callback would
89
still have to wait in the task queue until the call stack is empty
90
so just something to to keep in mind
91
so long story short the callbacks provided by web apis are pushed onto the task queue
92
when the asynchronous task completes so what about the promise based ones
93
if you haven't checked out my promises video yet i highly recommend you watch it
94
because i'll just assume some basic promise knowledge
95
while explaining this entire flow whenever we work with promises we're
96
working with the micro task queue the micro task queue is
97
a special queue dedicated to then catch finally callbacks a function
98
body execution after a weight the queue micro test callback
99
and the new mutation observer callback so only those callbacks
100
or those function body parts get pushed onto the micro task queue
101
so it's very specific however the event loop prioritizes the micro task queue
102
so whenever the call stack is empty the event loop first ensures
103
that the micro task queue is entirely empty
104
so it gets all the tasks from the micro task queue
105
moves them onto the call stack where they get executed
106
and only then will it move to the task queue
107
and after each task in the task queue it again checks the micro task queue
108
and a popular promise-based web api's fetch
109
so let's see what happens behind the scenes when we invoke fetch
110
so whenever we call fetch it's added to the call stack this is just responsible for creating a promise object
111
which by default is pending the result is undefined
112
and we don't have any promise reactions just yet it also
113
initiates the background network request that's handled by the browser then
114
we move on to the next line we have the den handler
115
and this creates a promise reaction record where we have res
116
console.log res the server still hasn't responded by the way
117
but we get to line four So there we have a synchronous console log end of script.
118
So now end of script is logged to the console.
119
And then finally the server returns some data.
120
So now the promise state is set to fulfilled.
121
The promise result is now the response object with the data that we got from the server.
122
And the promise reaction handler is now also pushed to the micro task queue, right?
123
Because it's a then callback and that gets pushed to the micro task queue.
124
The call stack is empty.
125
So the event loop checks the microtask queue, moves this to the call stack where it eventually logs the result that we got from the server.
126
Something to keep in mind with microtasks is that a microtask can also schedule another microtask.
127
And this means that the event loop is just constantly handling the microtask
128
and it can never actually get to the task queue.
129
It would just have to wait indefinitely.
130
So we're kind of creating an infinite loop, an infinite microtask loop, freezing our entire program.
131
I believe in node you can set like mextick depth
132
or something like that which prevents this exact thing from happening
133
but just make sure that you don't accidentally end up doing that.
134
And we can also promisify a callback based API.
135
So for example we can rep the get current position with a new promise constructor
136
and for the success callback and the error callback we just pass resolve and reject.
137
So this can be a pretty nice solution just to improve the readability within your code base a bit.
138
All right, a little quiz to see if you kind of understand it.
139
So we have a promise resolve with a den handler.
140
We have a set timeout.
141
We have a QMicroTask in which we have another QMicroTask, and then we have a console log 5.
142
It's up to you to see what gets logged.
143
So pause the video now and let's see if you got it right.
144
And the right answer is 5, 1, 3, 4, 2. So let's see why.
145
First, we have the promise resolve, and this just creates a new promise object that's instantly resolved.
146
Then on the next line, we have the den handler.
147
The promise is already resolved, so in the background, it does create that promise reaction, but the handler is immediately pushed to the microtask queue.
148
Then we have setTimeout, which is responsible for initiating that timer.
149
So the callback and the delay get passed to the API, and in the background, the browser starts some sort of timer.
150
Then we have queue microtask.
151
So the call is added to the call stack and this queues that callback to the microtask queue.
152
Then we have the synchronous console log 5.
153
So this gets pushed to the call stack and logs 5.
154
And in the meantime, the 10 milliseconds are up.
155
So the callback from setTimeout is pushed to the task queue.
156
Because this was a callback-based API, so task queue.
157
Our script is done.
158
The call stack is empty.
159
So the event loop checks the microtask queue.
160
And there we have the promise handler callback.
161
And this eventually calls console log 1.
162
So 1 is logged to the console.
163
Then we have the queue microtask callback and within this callback we call console log 3.
164
So 3 is logged to the console.
165
Then we call another queue microtask and this queues another microtask with its callback to the microtask queue.
166
However, the event loop has to ensure that the microtask queue is entirely empty before moving on to the task queue.
167
So that callback is immediately moved onto the call stack again and logs 4.
168
Now finally the call stack is empty and the microtask queue is empty
169
so the first available task from the task queue is moved onto the call stack and this eventually logs two.
170
So now we have 51342.
171
So let's just recap what we've covered so far.
172
So JavaScript is single-threaded.
173
It can only handle one task at a time.
174
We can use web APIs to interact with the features leveraged by the browser
175
and some of these APIs allow us to initiate async tasks in the background.
176
So the function call that initiates an async task like
177
that is still added to the call stack
178
but this is just to hand it off to the browser the actual async task is handled in the background
179
so it does not block the call stack the task queue
180
is used by callback based web apis to enqueue the callback
181
once the asynchronous task has completed then we have the micro task queue
182
which is only used by promise handlers the async function bodies after awaits the queue micro task queue callbacks
183
and the new mutation observer callbacks.
184
This queue has priority over the task queue and the event loop ensures
185
that this queue is entirely empty before moving on to the task queue.
186
And after handling each task from the task queue, the event loop again checks the microtask queue to ensure that nothing has been added in the meantime.
187
You often come across asynchronous JavaScript and if you aren't entirely sure why things execute a certain way, it might just be very discouraging.
188
But I hope Hope that my explanation for the task queue
189
and the micro task queue
190
and the event loop kind of helped you understand why certain parts of our code execute at a certain time.
191
Of course, as always, if you have any specific questions, feel free to reach out.
192
But I also highly recommend that you kind of just play around with it yourself.
193
Like try using setTimeout, try using queue micro task just to get a better sense of like, oh yeah, okay.
194
I understand why this runs at this time and why this doesn't execute stuff like that.
195
Good luck and have fun coding.

Who Should Watch This Video?

This video is perfect for intermediate English learners who want to boost their technical vocabulary while practicing listening and speaking. Whether you’re into coding or just curious about how JavaScript works, the clear, conversational explanation makes it easy to follow—even if you’re new to programming terms. It’s ideal for anyone using the shadowing technique to improve fluency, as the speaker’s pace is steady and the content is engaging enough to keep you focused.

Words & Idioms Worth Stealing

Here are key terms to add to your toolkit, plus everyday phrases that pop up in the video:

  • Notorious: Well-known for something bad (but here, it just means "widely discussed"). Example: "The event loop is a notorious topic, but it’s simpler than it sounds."
  • Offload: To pass a task to someone/something else. Example: "Web APIs let us offload long tasks to the browser."
  • Zoom out: To look at the big picture. Example: "When we zoom out, the event loop is just one part of the runtime."
  • Popped off: Removed quickly. Example: "The function is popped off the call stack once it’s done."

How to Get the Accent Right

The speaker uses a clear, neutral accent with natural pauses—great for shadowspeak practice. Focus on these tips: - Stress in multi-syllable words: "Asynchronous" (a-SYN-chro-nous) and "invocation" (in-vo-CA-tion) have stress on the second syllable. - Linking sounds: Notice how "call stack" becomes "callstack" in fast speech. Practice blending words like this to sound more natural. - Pace: The speaker slows down for technical terms—mirror this to emphasize key words. Use a shadowing site to record yourself and compare; it’s a quick way to improve English pronunciation! With consistent practice, you’ll not only understand JavaScript better but also speak English more confidently. Let’s get shadowing!

What is the Shadowing Technique?

Shadowing is a science-backed language learning technique originally developed for professional interpreter training and popularized by polyglot Dr. Alexander Arguelles. The method is simple but powerful: you listen to native English audio and immediately repeat it out loud — like a shadow following the speaker with just a 1–2 second delay. Unlike passive listening or grammar drills, shadowing forces your brain and mouth muscles to simultaneously process and reproduce real speech patterns. Research shows it significantly improves pronunciation accuracy, intonation, rhythm, connected speech, listening comprehension, and speaking fluency — making it one of the most effective methods for IELTS Speaking preparation and real-world English communication.

Shadowing technique: read the full step-by-step guide →