The event loop is the name of the runtime model that JavaScript uses to execute the code. The JavaScript engine basically does only one thing at a time and it has a system of messages, queues, and frames to determine what to execute and when.

Every time there’s a function call, the engine creates a “frame”. The frame contains all the internal variables and arguments for that function execution.

Now, what happens if there’s another function call inside? For example, if you call exampleFunctionA(), but inside that function, you call exampleFunctionB()?

A new frame is created for that new function call, on top of the previous one. And if that function has yet another function inside? You guessed it, the engine creates a new frame. Each time a function execution finishes, the runtime engine deletes its frame and resumes the execution of the parent function.

A group of related frames are called “stacks”. If you call exampleFunctionA(), which in turns calls exampleFunctionB(), which itself runs exampleFunctionC(), the frames for all three functions form a single stack.

When an event happens in the browser (i.e. mouse click, touchscreen tap, page load, drag and drop, etc.) and the event has an associated function, the engine creates a message (which contains the function call) and adds it to a queue, called “m.

Once the JavaScript engine finished executing everything, it starts to wait for incoming messages in the queue. If there’s only one single message, it processes that message right away. If the queue has many messages, it starts with the oldest one.

The engine executes the function in the message, creating the stack and as many frames as needed. Once all function calls are finished, it moves on to the next message (or waits for new messages if there aren’t any yet).

The setTimeout and setInterval functions also add messages to the queue. This means that those functions might have a delay if there are older messages in the queue. When an asynchronous task finishes, this also adds a new message to the queue.

An important aspect is that the JavaScript engine has to process every message completely before moving on to the next one. That means that, if a piece of code takes too much time, it blocks everything else!

If you have code that blocks the site, you could try to offload it to a web worker (as they have their own event loop, separate from the main page), or make use of asynchronous functions.