This was actually one of the interview question I was asked in an interview for a software engineer role at TikTok. Although I said this is the interview question you should know, I actually failed to explain clearly the correct output and how the event loop works lol.
I feel like event loop is the concept that people will always forget if we don't regularly refresh (at least for me, it is). Anyway, after the interview, I decided to refresh the concept again and write an article to strengthen my memory. I will explain event loop in a simplified way (I might skip some details).
Btw, the answer for this question above is at the very end.
It's responsible for parsing, interpreting, and executing JS code in browser or other environment. It translates JS to machine code that can be executed by computer.
Not really important here actually.
Obviously, it's a stack, which has "first-in, last-out" property. It's used to keep track of which functions are called and the order of function calls. When each function is called, it's pushed to the top of the call stack (precisely, a "frame" is pushed and it contains local variables, parameters, and other info about the function).
Example:
JS is a single-threaded language, only has one call stack, runs synchronously. To avoid a long-running task blocking other important tasks to run, JavaScript uses event loop mechanism. The idea is basically like this: pushing long-running tasks into a queue (which are task queue and microtask queue, we will get into that later), and only do this task IF the call stack is empty. Therefore, long-running tasks won't block the execution.
Event loop basically schedules tasks from task queue and microtask queue if the call stack is empty.
Callback-based Web API such as setTimeout(callback, delay)
will push the callback to the task queue after the browser finishes the execution.
Microtask is a specialized task queue which handles the callback in .then(callback)
, .catch(callback)
, .finally(callback)
, function body below await
(This is actually equivalent to .then(callback)
), and other microtasks(ignore now).
The callback will be pushed onto microtask queue once the promise is fulfilled (resolved).
Microtask queue has higher priority over task queue.
Promise.then()
and the function body after await
are basically the same thing. You can do the conversion in your brain if you have trouble solving this kind of interview problem.
Alright. We've already got the minimal knowledge about the event loop to solve this problem. Let's breakdown what will happen when we run this:
func1
and func2
(haven't been called yet).script start
1️⃣setTimeout
which has delay equals to 0 ms. This means, after 0 ms, the callback will be pushed onto task queue.
[ console.log("timeout") ]
func3
and func4
.func1
and func2
, which are easy cases since it runs synchronously.
func1
2️⃣ and func2
3️⃣func3
onto call stack
func4
onto call stack, which return a Promise<void>
since it's an async function.func4
4️⃣[ console.log("func3") ]
new Promise()
.
promise 1
5️⃣.then()
onto microtask queue.[ console.log("func3"), console.log("promise 2") ]
script end
6️⃣func 3
7️⃣ and promise 2
8️⃣timeout
9️⃣So the answer is:
await
in async
function will be pushed into the microtask queue when the Promise we are currently waiting is fulfilled. (Just like how .then()
works.)