Back to blog
· 4 min read

Javascript Execution Model

javascript

Summary

The javascript language offers a level of abstraction that allows developers to write simple code without worrying too much about how it is handled behind the scenes. As things get more complex, it helps to understand more about the fundamentals of how the code execution happens.

Call Stack

Javascript is single-threaded. It can only perform one task at a time. During script execution, it utilizes the call stack to keep track of code execution. At a high level, the engine works its way from top to bottom of a script. Execution contexts, functions are pushed and popped from the call stack, allowing the engine to keep track of where it is and what needs to execute.

Execution Context

The execution context, as the name implies, is the container in which a script runs. When a script first runs, the Global Execution Context is created. When functions in a script are run, their execution contexts are created within the global context.

The context consists of two phases:

  • Creation Phase
  • Execution Phase

Global Context (Creation Phase)

  • Instantiate the global object (window in browsers, global in node)
  • Create this object and bind it to the global object **
  • Instantiate the memory heap for variables, functions
  • Store function declarations, variables in the heap.
    • Variables defined using var are instantiated as undefined. Variables defined with let or const are NOT instantiated.

Global Context (Execution Phase)

  • Execute script from top to bottom
  • Assign values to variables
  • Execution Function Calls
    • Create Function Execution Contexts

Function Context (Creation Phase)

  • Instantiate arguments object as reference to all parameters of the function
  • Initialize parameters as undefined

Function Context (Execution Phase)

  • Same as global, but within the scope of the global execution context

** I was initially confused as to why this would need to be bound to the global object (it seemed redundant). The answer is pretty obvious after looking into it. Javascript uses the this keyword as a pointer/reference that allows functions a way to interact with the object calling them. Essentially, a generic reference pattern that can be used across all functions. At the global level, the parent object is the global object itself. Thus, this is bound to the global object.

Event Loop

As mentioned earlier, the javascript engine is single threaded. Javascript runtimes, however, use multiple threads to afford things such as I/O and timers without blocking execution.

At a high level, the java script event loop continuously runs, checking for items on the call stack and executing them. Callbacks and other async requests are queued up in the callback queue. The items in this queue are only executed when the call stack is empty.

To take a concrete example, we can look at a function that uses setTimeout

function bar() {
    console.log("Callback executed!");
}

function foo() {
    setTimeout(bar, 0);
}

console.log("Starting...");
foo();
console.log("Done!");

In the above example, you may be surprised to learn that the order of console logging will appear as

Starting...
Done!
Callback executed!

especially when considering the timeout value is set to 0ms.

The JS engine makes the request to the TimerAPI (responsible for handling the setTimeout function). This API creates the timer and handles placing the defined callback function (bar in this example) into the callback queue once the timer has expired.

The engine makes the request to the Timer API and moves on immediately, printing Done! to the console. Only then does it check the callback queue and begin processing the queued bar function. In fact, you could call as many synchronous functions as you wanted after calling the foo, and they would all execute before the bar function.

Conclusion

This overview has been fairly high level. There is a good deal more nuance and technical details that could be delved into. At some point, I'd like to revisit this post and add more detail, or create a separate post on the differences between traditional callbacks, promises, and async/await.


No comments yet.

Leave a comment