I am learning JavaScript on Exercism and recently got confused by how the JavaScript event loop works. When I use things like setTimeout, Promises, and async/await together, the order of the output in the console is not always what I expect.
This makes me feel like I donât fully understand whatâs happening behind the scenes.
For example, I thought that setTimeout with zero delay would run immediately, but a Promise still finishes first.
I later read that this is because Promises go in the microtask queue, while timeouts go in the macrotask queue. Even though I read about it, I still find it tricky to remember and explain clearly. Checked JavaScript execution model guide for reference.
So, I want to ask: how do you learn and remember the event loop in a simple way? I know many people begin by asking what is javascript but for me this is the next important step to get better.
Any easy examples, tips, or good resources would be really helpful.
For the setTimeout, I remember that whenever I add something to that, Iâm adding to a queue. And that queue wonât run until whatever the main code thatâs running has finished. So I think of setTimeout(..., 0) as âAdd this to a queue to run immediately (0) once the current code is finishedâ.
For async/await/promises, the whole point really is that you donât need to think about when they run. In fact, you actively donât want to anticipate that. You maybe want to think of them more like being a setTimeout(... rand(0, 10)), so the code might run (or complete) at sometime in the future and you have no idea when.
From a technical perspective, I think of three things:
The current running code (this takes priority)
Anything that happens on a timer (setTimeout, setInterval, requestAnimationFrame, etc)
Code thatâs waiting to finish (e.g. Promises waiting to resolve).
Then:
(1) just chugs along until it finishes
Then the first thing ready in (2) or (3) becomes (1) and we restart the sequence.
Itâs more complex under the scenes, but if you think of it in terms of âthereâs some code running and then thereâs things waiting to runâ, youâre basically going to have 99.9% of use-cases covered much more simply.
Try to figure out the logs BEFORE you press run (and then press step / auto step).
BFC ADE
I think the hardest thing for people to grasp is that in this visualiser that the 1 ms call still happens before the next 0 ms call. You can change it to 10000 (10 seconds) to make it work as expected.
To add to the explanation by Jeremy:
promises try to execute as âsoon as they are readyâ. There is never a timer associated. This is why they go into the microtasks list and this is why I donât call this âschedulingâ, they are queued to be executed asap. A promise that does not do I/O (read from disk, query the interwebs, etc.) or has a manual delay (setTimeout(resolve), requestAnimationFrame(resolve), etc.), will always âinstantlyâ be ready, and thus execute as soon as possible.
setTimeout (and setInterval etc.) are timers. They do not mean âexecute after x msâ. They mean: âI want x ms to pass before I executeâ. This is always scheduling. It cannot pick up something from the scheduled list until the queued tasks are done.
I think if you separate queuing from scheduling, it becomes easier!