Motivating the Event Loop in JavaScript
- There are many differences between how Python and JavaScript handle events
- However, there are many similar components that are roughly comparable
- Personally, it helps knowing both models in order to build a broader understanding of the general architecture of event loops
-
The following is the general interaction between:
- The JavaScript engine
- The event loop
- Any WebAPIs
Describing the Heap
-
The heap is memory set aside for dynamic allocation
- The stack is memory set aside for static allocation
- The stack stores primitives, like ints and strings
- The heap stores objects
- Primitives usually involve stack memory allocation, since we usually know how large they will be
- Objects usually involve dynamic memory allocation, since they usually change in size throughout the code
-
There's no enforced pattern to the allocation and deallocation of blocks from the heap
- This is different from the call stack
- We can allocate a block at any time and free it at any time
- Each thread gets a call stack
- On the other hand, there's typically only one heap for the application
Describing the Call Stack
- The call stack is a LIFO queue (Last In, First Out)
-
JavaScript has a single call stack that does the following:
- Keeps track of what function we're currently executing
- Keeps track of what function is to be executed after
- When a function is about to be executed, it is added to the call stack
- Next, if a function calls another function, then the called function will be on the top of the call stack
Describing the Event Table
- Every time an async function gets called, it is added to the event table
- For example, calling
setTimeout()
will get added to the event table immediately - The event table is a data structure that tracks what functions should be called after a function finishes executing
- In other words, it knows that a certain function should be triggered after an event
-
The following are examples of events:
- Timeout
- Click
- Mouse movement
- Once that event occurs, the event is added to the event queue
-
Note, the event table doesn't do the following:
- Executes functions
- Adds them to the call stack
-
It's only purpose is to do the following:
- Tracks events
- Sends events to the event queue
Describing the Event Queue
- The event queue is a data structure similar to the call stack
- However, the event queue is more designated for asynchronous functions (i.e. events)
- The event queue is a FIFO queue (First in, First out)
- By doing this, the event queue stores the order in which functions should be executed
- As stated previously, the event queue receives function calls from the event table
-
It is responsible for the following:
- Storing functions for the event loop to monitor
- Informing the event loop when there are events available
Describing the Event Loop
- The event loop is a constantly running process that checks if the call stack is empty
- Imagine the event loop is a clock
- Every time the clock ticks, it looks at the call stack
- And, if it is empty, it looks into the event queue
- If there is an event in the event queue, then the event loop sends the event to the call stack to be executed
- Otherwise, nothing happens
Blocking the Event Loop
- The even loop will be blocked if code takes too long to be executed in the call stack
- This is because events will build up in the event queue, but the event loop will never move them to the call stack (since it's full)
- Specifically, this is because JavaScript is single-threaded
- However, nearly all of the I/O primitives in JavaScript are non-blocking
- Meaning, JavaScript code with primitives won't face the problem mentioned above
-
The following are examples of I/O primitives:
- Network requests
- Node.js filesystem operations
- This is why JavaScript is based so much on callbacks (i.e. code has a small chance of being blocked)
tldr
-
The call stack is responsible for the following
- Tracking what function are currently being executed
- Tracking what function is to be executed afterwards
-
The event table is responsible for the following:
- Tracking events
- Sending events to the event queue
-
The event queue is responsible for the following:
- Storing functions for the event loop to monitor
- Informing the event loop when there are events available
- The event loop is a constantly running process that checks if the call stack is empty
-
The event loop does the following:
- Checks to see if there is space to push to the call stack
- If there is space, it looks if there is an event in the event queue
- If there is an event, then it sends the event to the call stack
References
Previous