The Call Stack
If you are reading this article it is more than likely that you know what a call stack is. Still, let’s remind ourselves of its key features:
- It is a LIFO (last in first out) collection, with two primary operations: ‘push’ and ‘pop’.
- When a function begins its execution, a new frame is pushed onto the stack.
- That frame is used to store local variables, parameters and a return address (of the calling function).
- If function a calls function b, then a new frame for function b is pushed onto the stack above the frame for function a.
- When function b completes, its frame is popped off, and execution continues from the return address stored in it.
- So, if we have a function a which calls function b, then during the execution of function b, the stack will look like this:
The Message Queue
A message is only moved from the message queue to the call stack when the call stack is empty.
Is this a reasonable assumption? In most cases, yes. The only long-running operations I can think of which would not involve I/O would be processing an enormous array, or calling a recursive function many times. An example of the latter, computing Fibonacci numbers, is discussed here, including a discussion of some possible solutions to the problem.
The Event Loop
The success of Node.js would suggest that this approach largely works, although I’m sure there are some cases, involving heavy mathematical processing for example, where it could be problematic.