How JavaScript and TypeScript Are Executed: A Deep Dive for Web Developers

Java Script

March 13, 2025

How JavaScript and TypeScript Are Executed: A Deep Dive for Web Developers

How JavaScript and TypeScript Are Executed: A Deep Dive for Web Developers

JavaScript is the backbone of modern web development, enabling interactive, dynamic, and scalable applications. However, many developers—especially those new to JavaScript or transitioning from other languages—struggle to understand how JavaScript and TypeScript are executed. This article will break down the execution process of JavaScript and TypeScript in detail, covering key concepts such as interpretation, Compilation, Just-In-Time (JIT) compilation, and TypeScript transpilation.

  1. JavaScript Execution: The Core Concepts

1.1 JavaScript as an Interpreted Language: Understanding How It Works

JavaScript is often called an interpreted language, meaning its code is executed line by line without requiring an explicit compilation step before running. However, this is an oversimplification. Modern JavaScript engines, such as V8 (used in Chrome and Node.js), SpiderMonkey (Firefox), and JavaScriptCore (Safari), use a combination of interpretation and Just-In-Time (JIT) compilation to improve performance.

Let’s break down what it means for JavaScript to be interpreted and how modern execution engines optimize it.


What Does "Interpreted" Mean?

In traditional programming terms, a language is considered interpreted if its source code is executed directly by an interpreter without first being compiled into machine code. This differs from compiled languages like C, Rust, or Java, where the code is first translated into a lower-level binary format before execution.

Key Characteristics of Interpreted Languages:

  1. Line-by-Line Execution: The code is processed and executed statement by statement rather than compiled simultaneously.
  2. No Explicit Compilation Step: Unlike C++, which requires a separate compilation phase before execution, JavaScript code is executed on the fly.
  3. Platform Independence: JavaScript does not need to be compiled into different binaries for different operating systems. The same JavaScript code can run across browsers and environments (e.g., Node.js).
  4. Dynamic Typing & Late Binding: Since JavaScript is interpreted at runtime, types are determined dynamically, and function bindings can be resolved late in the execution process.

However, while JavaScript is often described as an interpreted language, modern JavaScript engines do not simply interpret code line-by-line. Instead, they use Just-In-Time (JIT) Compilation, which means the code is compiled into bytecode and then optimized for performance.


How JavaScript Is Executed in an Engine

When JavaScript runs in a browser or a JavaScript runtime like Node.js, it follows these main steps:

1. Tokenization (Lexical Analysis)

  • The JavaScript engine scans the source code and breaks it into tokens—the smallest units of meaningful code, such as keywords, operators, and identifiers.
  • Example: The code

Loading...

It is tokenized into:

  • Loading...

    (keyword)
  • Loading...

    (identifier)
  • Loading...

    (operator)
  • Loading...

    (literal)
  • Loading...

    (delimiter)

2. Parsing and AST (Abstract Syntax Tree) Generation

  • The tokens are converted into a structured representation called an Abstract Syntax Tree (AST).
  • The AST is a hierarchical tree representation of the code, making it easier to analyze and execute.
  • Example AST for

    Loading...

    :

Loading...

3. Interpretation vs. Compilation

Once the AST is built, traditional interpreters execute the code line by line. However, JavaScript engines like V8 use a hybrid approach combining interpretation and JIT compilation.

  • Older JavaScript Engines (Pure Interpretation Approach)

    • The interpreter would directly execute each statement one at a time.
    • This was slower since every execution required interpreting the code again.
  • Modern JavaScript Engines (JIT Compilation)

    • The engine compiles the AST into bytecode using a baseline interpreter (e.g., Ignition in V8).
    • If the code is executed multiple times, the JIT compiler (e.g., TurboFan in V8) further optimizes it by compiling frequently executed code into machine code for better performance.

4. Execution and Optimization

  • The bytecode is executed by the JavaScript Virtual Machine (JVM) inside the engine.
  • Frequently executed code is optimized and converted into machine code for faster execution.
  • JavaScript engines also perform Garbage Collection, removing unused objects to free up memory.

Comparing Interpretation vs. Compilation

FeatureInterpreted Languages (Traditional)JavaScript in Modern Engines (JIT Compilation)
ExecutionLine-by-line, real-time executionInitially interpreted, later compiled
PerformanceSlower due to repeated parsingFaster due to compiled optimizations
Compilation StepNone, executes immediatelyPartial compilation using JIT
OptimizationMinimalUses advanced optimization techniques

While JavaScript behaves like an interpreted language at first, the JIT compiler significantly improves performance by compiling frequently executed code into machine code.


How Modern JavaScript Engines Handle Execution

How does the V8 JavaScript engine (used in Chrome and Node.js) handle JavaScript execution?

V8 Execution Process

  1. Parsing & AST Generation
    • The JavaScript code is parsed and converted into an AST.
  2. Bytecode Compilation (Ignition Interpreter)
    • Instead of executing JavaScript directly, V8 converts it into an intermediate form called bytecode.
  3. Execution & Profiling
    • The engine executes the bytecode and monitors frequently used functions (hot code).
  4. Optimization (TurboFan Compiler)
    • If a certain code is executed multiple times, V8 optimizes it using TurboFan to compile it into machine code.
  5. Deoptimization
    • If the optimized code's assumptions are incorrect, V8 de-optimizes and falls back to bytecode execution.

Example: Understanding JavaScript Execution

Let’s take a simple example and analyze how it is executed.

JavaScript Code Example

Loading...

Execution Breakdown

  1. Tokenization & Parsing
    • The function

      Loading...

      is broken into tokens and converted into an AST.
  2. Bytecode Compilation
    • The function is interpreted and compiled into bytecode.
  3. Execution
    • The

      Loading...

      function is executed, and the result (

      Loading...

      ) is printed.
  4. Optimization
    • If

      Loading...

      is called multiple times, the function is compiled into machine code for faster execution.

Why Does This Matter?

Understanding how JavaScript executes in a modern engine helps developers:

  • Write optimized and performant code.
  • Avoid common performance pitfalls, such as blocking the main thread.
  • Make informed decisions when writing JavaScript applications.

While JavaScript started as a purely interpreted language, modern engines use JIT compilation to significantly boost execution speed. Knowing how JavaScript engines work can help you write better, more efficient applications and debug performance bottlenecks effectively.

1.2 JavaScript Execution in the Browser: A Detailed Breakdown

JavaScript plays a crucial role in modern web development by enabling interactive and dynamic behavior in web pages. Unlike languages that require manual compilation (such as C++ or Java), JavaScript is executed directly within the browser and inside a JavaScript engine. However, this process involves multiple steps, including parsing, Compilation, execution, and Optimization.

This section will provide an in-depth breakdown of how JavaScript is executed in a web browser, covering topics such as the JavaScript engine, execution context, event loop, call stack, and optimizations.


1. The JavaScript Engine Inside a Browser

Each browser has its own built-in JavaScript engine that is responsible for executing JavaScript code. Some of the most popular engines include:

  • Google Chrome & Edge: V8 Engine
  • Mozilla Firefox: SpiderMonkey
  • Safari: JavaScriptCore (Nitro)
  • Opera: V8 (since it is Chromium-based)
  • Legacy Microsoft Edge: Chakra

Although these engines are built differently, they all follow a similar process when executing JavaScript in the browser.


2. How JavaScript Code Is Executed in a Browser

When a browser encounters JavaScript in a webpage (inside

Loading...

tags or external JS files), the following steps take place:

Step 1: Fetching the JavaScript Code

  • The browser downloads the JavaScript file from the server.
  • If the JavaScript is inline (

    Loading...

    in an HTML file), it is read directly.
  • If the JavaScript file is external (

    Loading...

    ), it is downloaded asynchronously (unless the script is blocking).

Step 2: Parsing (Lexical Analysis & Syntax Analysis)

Once the browser has the JavaScript source code:

  1. Lexical Analysis (Tokenization)
    • The JavaScript engine scans the code and breaks it into tokens (smallest units like keywords, operators, and identifiers).
    • Example for

      Loading...

      :

Loading...

  1. Syntax Analysis (Parsing & AST Generation)
    • The tokens are analyzed and converted into an Abstract Syntax Tree (AST), a structured representation of the code.
    • Example AST for

      Loading...

      :

Loading...

The AST is used to understand the code’s structure before execution.

Step 3: Compilation (JIT Compilation)

JavaScript is not purely interpreted—modern engines use Just-In-Time (JIT) compilation to improve execution speed.

  • The Ignition Interpreter in V8 initially interprets the JavaScript into bytecode.
  • If certain parts of the code are executed frequently, the TurboFan Compiler compiles them into machine code for better performance.

This hybrid approach improves efficiency, as only frequently executed code is compiled.

Step 4: Code Execution

After Compilation, JavaScript is executed in the browser using the following components:

Execution Contexts

JavaScript runs inside an Execution Context, which determines how variables and functions are accessed.
There are three main execution contexts:

  1. Global Execution Context (GEC) – Created for the main script.
  2. Function Execution Context (FEC) – Created whenever a function is invoked.
  3. Eval Execution Context – Created when

    Loading...

    is used (though rarely recommended).

Call Stack

The Call Stack tracks function execution. When a function is called, it is pushed onto the stack, and when it finishes, it is popped off.

Example:

Loading...

Execution flow in the Call Stack:

  1. Loading...

    is called → added to the stack.
  2. Loading...

    is called → added to the stack.
  3. Loading...

    returns

    Loading...

    → removed from the stack.
  4. Loading...

    returns

    Loading...

    → removed from the stack.
  5. Loading...

    executes and prints

    Loading...

    .

Heap Memory

  • JavaScript uses Heap Memory to store objects.
  • The Garbage Collector automatically removes unused objects using the Mark-and-Sweep Algorithm.

3. Handling Asynchronous JavaScript: The Event Loop

Since JavaScript is single-threaded, it uses the Event Loop to handle asynchronous operations.

Key Components of Asynchronous Execution

  1. Call Stack – Handles function execution.
  2. Web APIs – Browser features like

    Loading...

    ,

    Loading...

    , and DOM manipulation.
  3. Callback Queue – Holds functions waiting to be executed after Web API tasks are complete.
  4. Event Loop – Moves completed tasks from the Callback Queue to the Call Stack.

Example of Event Loop Execution

Loading...

Execution Order:

  1. Loading...

    is logged.
  2. Loading...

    is sent to the Web API (timer starts).
  3. Loading...

    is logged.
  4. After 1000ms, the callback (

    Loading...

    ) moves to the Callback Queue.
  5. The Event Loop moves it to the Call Stack when it's empty and executes.

This mechanism prevents JavaScript from blocking while waiting for time-consuming operations.


4. JavaScript Optimization in the Browser

Modern JavaScript engines use various techniques to optimize performance:

1. Just-In-Time (JIT) Compilation

  • JavaScript is compiled into bytecode, which is then executed.
  • Frequently used code is compiled into machine code by TurboFan (V8’s optimizing compiler).

2. Hot Code Optimization

  • Frequently executed functions are optimized for speed.
  • Example: Loop unrolling optimizes repeated code execution.

3. Hidden Class Optimization

  • JavaScript objects are dynamic, but engines create hidden classes to optimize object property access.

Example:

Loading...

V8 optimizes this by assigning a hidden class to

Loading...

, reducing lookup times.

4. Inline Caching

  • Frequently accessed properties are cached for faster access.

5. Garbage Collection

  • The Mark-and-Sweep Algorithm removes unused objects from memory.

5. Common Performance Pitfalls in JavaScript Execution

  • Blocking the Main Thread – Avoid synchronous operations (

    Loading...

    loops, large computations).
  • Too Many Repaints & Reflows – Minimize DOM updates in loops.
  • Memory Leaks – Use weak references and

    Loading...

    unused variables.
  • Unoptimized Loops – Prefer

    Loading...

    or

    Loading...

    over traditional loops for better performance.

Understanding JavaScript execution in the browser is crucial for writing efficient code. The browser follows these steps:

  1. Fetch JavaScript from an external file or inline

    Loading...

    tag.
  2. Parse & Compile it into bytecode.
  3. Execute it in an execution context (Call Stack & Heap).
  4. Handle Asynchronous Tasks via the Event Loop.
  5. Optimize execution using JIT compilation, caching, and garbage collection.

By mastering these concepts, developers can write faster, more efficient, and bug-free JavaScript for modern web applications.

1.3 JavaScript Execution in Node.js: A Deep Dive

JavaScript is executed in web browsers and runs on servers using Node.js. Unlike browsers, which execute JavaScript in the context of a webpage, Node.js is a runtime environment that allows JavaScript to run outside the browser. It enables server-side development, file system access, networking, and more.

In this section, we’ll explore:

  • How JavaScript is executed in Node.js
  • The V8 engine in Node.js
  • The role of Libuv and asynchronous I/O
  • The Event Loop in Node.js
  • Optimizations used in Node.js

1. How JavaScript Executes in Node.js

When JavaScript runs in Node.js, the execution process differs slightly from that of browsers. While browsers provide JavaScript with APIs to manipulate the DOM and handle user interactions, Node.js provides APIs for file system operations, networking, and process management.

When a JavaScript file is executed in Node.js, the following steps occur:

  1. Node.js Loads the JavaScript File
    • The file is loaded into memory from the disk.
    • Example:

Loading...

  • The script

    Loading...

    is read by Node.js.
  1. The V8 Engine Parses and Compiles JavaScript

    • The V8 engine (used in Node.js) parses and compiles the JavaScript code using a Just-In-Time (JIT) compiler.
    • It converts the script into an Abstract Syntax Tree (AST) and compiles it into bytecode.
  2. Execution Begins in the Global Execution Context

    • The script runs inside the Global Execution Context, and Node.js starts executing the code.
  3. Node.js Uses Libuv for Asynchronous I/O

    • Unlike the browser, which relies on the Web API for async operations, Node.js uses Libuv, a C++ library that provides:
      • Asynchronous I/O (e.g., file system, TCP, UDP, DNS)
      • Thread Pool for expensive tasks
      • Timers (

        Loading...

        ,

        Loading...

        )
      • Event Loop to handle callbacks efficiently
  4. The Event Loop Manages Execution Flow

    • JavaScript is single-threaded, but Node.js handles concurrent tasks using the Event Loop.
    • The Event Loop coordinates synchronous and asynchronous tasks.
  5. Garbage Collection Frees Up Memory

    • The V8 garbage collector automatically clears unused objects.

2. The V8 JavaScript Engine in Node.js

What Is V8?

  • V8 is Google’s high-performance JavaScript engine, written in C++.
  • It compiles JavaScript into machine code instead of interpreting it.
  • V8 consists of:
    • Ignition Interpreter: Converts JavaScript into bytecode.
    • TurboFan Optimizing Compiler: Transforms frequently executed code into optimized machine code.

V8 Execution Flow in Node.js

  1. Lexical Analysis & Parsing
    • JavaScript code is tokenized and converted into an Abstract Syntax Tree (AST).
  2. Bytecode Compilation
    • The AST is compiled into bytecode by the Ignition Interpreter.
  3. JIT Compilation for Hot Code
    • Frequently used functions are optimized by TurboFan and compiled into machine code.

3. The Role of Libuv in Node.js Execution

What Is Libuv?

Libuv is a C++ library that powers Node.js's non-blocking I/O model. It provides:

  • Asynchronous I/O operations (File system, TCP, UDP, DNS)
  • Thread Pool (for CPU-intensive tasks)
  • Event Loop (handles callbacks)
  • Timers API (

    Loading...

    ,

    Loading...

    )

How Libuv Works in Node.js

  1. When Node.js encounters an I/O operation, like reading a file:

Loading...

  1. Libuv handles the file operation asynchronously.
  2. Node.js does not wait for the file to be read.
  3. The Event Loop queues the callback (

    Loading...

    ) when the file is ready.
  4. "Reading file..." is logged first, then the file content appears later.

4. The Event Loop in Node.js

The Event Loop is the heart of Node.js, managing asynchronous tasks.

Understanding the Node.js Event Loop

The Event Loop cycles through phases:

  1. Timers Phase: Executes

    Loading...

    and

    Loading...

    callbacks.
  2. Pending Callbacks Phase: Executes I/O-related callbacks.
  3. Idle & Prepare Phase: Internal engine tasks.
  4. Poll Phase: Handles I/O (file system, network requests).
  5. Check Phase: Executes

    Loading...

    callbacks.
  6. Close Callbacks Phase: Executes close events (e.g.,

    Loading...

    ).

Example of the Event Loop in Action

Loading...

Execution Order:

  1. Loading...

    is printed.
  2. Loading...

    is printed.
  3. The Event Loop moves to the Check Phase before the Timers Phase, so ``Immediate Callback

    Loading...

    Timeout Callback`.

5. Node.js Execution Optimization Techniques

To improve performance, Node.js and the V8 engine implement several optimizations:

1. JIT Compilation

  • Ignition interprets bytecode for quick execution.
  • TurboFan optimizes frequently used code.

2. Hidden Classes & Inline Caching

  • Objects dynamically create hidden classes for faster property access.
  • Frequently accessed properties are cached for speed.

3. Efficient Memory Management & Garbage Collection

  • V8 uses Mark-and-Sweep for automatic garbage collection.

4. Worker Threads for CPU-Intensive Tasks

  • Node.js is single-threaded but uses Worker Threads for parallel execution.
  • Example:

Loading...

5. Streams for Efficient Data Handling

  • Node.js uses streams to handle large data sets efficiently.

6. Node.js Execution vs. Browser Execution

FeatureBrowser (Chrome, Firefox)Node.js
Execution EnvironmentRuns inside a web browserRuns as a standalone runtime
JavaScript EngineUses V8, SpiderMonkey, JavaScriptCoreUses V8
APIs AvailableDOM,

Loading...

, Web APIs
File system, networking, process management
Asynchronous HandlingEvent Loop + Web APIsEvent Loop + Libuv
Thread ModelSingle-threaded with Web WorkersSingle-threaded but supports Worker Threads

7. Summary

How JavaScript is Executed in Node.js

  1. JavaScript is parsed into an AST.
  2. Bytecode is generated using the V8 engine.
  3. Execution starts in the Global Execution Context.
  4. Asynchronous I/O operations are delegated to Libuv.
  5. The Event Loop coordinates execution.
  6. Garbage Collection manages memory.

Key Takeaways

  • Node.js is built on V8 but extends JavaScript with Libuv for non-blocking I/O.
  • The Event Loop enables asynchronous programming without multi-threading.
  • Worker Threads can handle CPU-intensive tasks.
  • Optimizations like JIT compilation and inline caching improve execution speed.

Understanding how JavaScript executes in Node.js helps developers write efficient, optimized, and scalable server-side applications.

2. Understanding the JavaScript Engine and JIT Compilation

2.1 Steps in JavaScript Execution (V8 Engine as Example)

The V8 JavaScript Engine, developed by Google, is an open-source high-performance JavaScript engine used in Google Chrome, Microsoft Edge, and Node.js. Unlike traditional interpreted languages, JavaScript in V8 undergoes a complex execution process involving parsing, Compilation, interpretation, Optimization, and garbage collection.

This section breaks down the step-by-step execution process of JavaScript inside the V8 engine. Understanding these steps helps developers write optimized, high-performance JavaScript applications.


Step 1: Tokenization (Lexical Analysis)

Before execution, the V8 engine scans the JavaScript code and breaks it into meaningful units called tokens.

What Are Tokens?

Tokens are the smallest building blocks of JavaScript syntax, including:

  • Keywords:

    Loading...

    ,

    Loading...

    ,

    Loading...

  • Identifiers:

    Loading...

    ,

    Loading...

  • Operators:

    Loading...

    ,

    Loading...

    ,

    Loading...

    ,

    Loading...

  • Literals:

    Loading...

    ,

    Loading...

  • Delimiters:

    Loading...

    ,

    Loading...

    ,

    Loading...

Example of Tokenization

Consider this JavaScript code:

Loading...

The V8 engine breaks it down into tokens:

Loading...

Each token is identified with its type (e.g.,

Loading...

is a keyword,

Loading...

is an identifier).


Step 2: Parsing and Abstract Syntax Tree (AST) Generation

After tokenization, the engine creates an Abstract Syntax Tree (AST), a structured representation of the code.

What Is an AST?

An AST is a tree-like data structure that represents the syntactic structure of the JavaScript code.

Example of AST Generation

For the JavaScript code:

Loading...

The AST looks like:

Loading...

Each node represents a part of the code.

Why Is AST Important?

  • AST helps detect syntax errors before execution.
  • It enables JavaScript minification and Optimization.
  • Tools like Babel, ESLint, and Prettier use ASTs to transform and lint code.

Step 3: Bytecode Compilation (Ignition Interpreter)

Once the AST is generated, the JavaScript engine does not execute JavaScript directly. Instead, it compiles the AST into bytecode.

What Is Bytecode?

Bytecode is an intermediate representation of JavaScript, optimized for execution but not yet machine code.

How Does Ignition Work?

  • The Ignition Interpreter translates the AST into bytecode.
  • Bytecode is a more efficient representation of JavaScript than raw source code.
  • Example of JavaScript Bytecode (Simplified):

Loading...

Ignition compiles this into bytecode instructions like:

Loading...

  • Ignition interprets and executes this bytecode immediately.

Why Does V8 Use Bytecode?

  • Bytecode is faster than interpreting JavaScript directly.
  • It allows the engine to optimize performance dynamically.
  • Hot code (frequently executed code) can be optimized further.

Step 4: Optimizing Compilation (TurboFan)

Once the script starts running, V8 identifies "hot code"—code that executes frequently—and optimizes it further.

How TurboFan Optimizes Code

  1. Profile and Identify Hot Code
    • If a function runs multiple times, V8 marks it as "hot."
  2. Optimize into Machine Code
    • TurboFan compiles hot code into highly efficient machine code.
  3. Inline Caching
    • TurboFan caches frequently used properties for faster access.

Example of Optimization

Consider this function:

Loading...

Since

Loading...

runs multiple times, TurboFan compiles it into machine code, making it much faster.

Deoptimization: When Optimized Code Fails

  • If V8 makes incorrect assumptions about the code (e.g., assuming a variable is always a number but later finding a string), it de-optimizes the function back to bytecode.
  • Example:

Loading...

  • V8 initially optimizes

    Loading...

    assuming both arguments are numbers
    .
  • When

    Loading...

    is executed, V8 realizes

    Loading...

    is now a string concatenation operator, forcing it to deoptimize the function.

Step 5: Garbage Collection (Memory Management)

JavaScript automatically manages memory using Garbage Collection (GC).

How Does Garbage Collection Work?

  1. JavaScript allocates memory for variables and objects.
  2. When objects are no longer needed, V8 frees memory.
  3. The "Mark-and-Sweep" Algorithm removes unused objects.

Example of Garbage Collection

Loading...

  • Loading...

    initially holds an object.
  • After setting

    Loading...

    , the object becomes unreachable, and garbage collection removes it.

Optimized Memory Management

  • Generational Garbage Collection: V8 categorizes objects as "young" or "old" and cleans them accordingly.
  • Incremental & Concurrent GC: V8 cleans memory in small chunks to avoid performance slowdowns.

Summary of V8 Execution Steps

StepProcessComponent Involved
1. TokenizationBreaks JavaScript into tokensTokenizer (Lexer)
2. Parsing (AST Generation)Converts tokens into a structured treeParser
3. Bytecode CompilationConverts AST into an intermediate formatIgnition Interpreter
4. Optimized compilationConverts frequently used code into machine codeTurboFan Compiler
5. Garbage CollectionRemoves unused objects to free memoryOrinoco Garbage Collector

Understanding JavaScript execution in V8 helps developers:

  • Write high-performance JavaScript by avoiding unnecessary optimizations.
  • Prevent deoptimization issues by maintaining type consistency.
  • Reduce memory leaks by managing objects efficiently.

By leveraging V8’s optimizations, JIT compilation, and garbage collection, JavaScript developers can write fast, memory-efficient applications for both browsers and Node.js.

2.2 How JIT Compilation Works in V8

Modern JavaScript engines, such as V8 (Chrome, Node.js), SpiderMonkey (Firefox), and JavaScriptCore (Safari), do not simply interpret JavaScript line by line. Instead, they use a Just-In-Time (JIT) compilation approach, which combines interpretation and compilation to improve execution speed.

JIT compilation allows JavaScript to run faster than a traditional interpreted language while maintaining the flexibility of dynamic typing. In this section, we’ll break down how JIT compilation works in the V8 engine.


1. What Is JIT Compilation?

Traditional Interpretation vs. Compilation

  • Interpreted languages (e.g., Python, Ruby) execute code line-by-line, which makes execution slower because every statement needs to be processed each time it runs.
  • Compiled languages (e.g., C, Rust) translate the entire source code into machine code before execution, making it much faster, but requiring a separate compilation step.

JIT Compilation: The Best of Both Worlds

JIT Compilation (Just-In-Time Compilation) is a hybrid approach that:

  • Interprets JavaScript initially for faster startup.
  • Compiles frequently executed (hot) code into optimized machine code for better performance.

How JIT Compilation Improves JavaScript Performance

  1. Fast Startup: JavaScript begins executing immediately through an interpreter.
  2. Code Optimization: Frequently used code paths are compiled and optimized dynamically.
  3. Adaptive Execution: JIT continuously profiles and refines optimizations during execution.

2. JIT Compilation Process in V8

V8 uses a multi-tier JIT compiler architecture:

  1. Ignition Interpreter → Converts JavaScript into bytecode.
  2. TurboFan Compiler → Optimizes hot functions into high-performance machine code.
  3. Deoptimization Mechanism → Reverts compiled code to bytecode if assumptions are incorrect.

Let’s explore each stage in detail.


3. Ignition: The JavaScript Interpreter

  • When JavaScript code is executed, V8 does not immediately compile it into machine code.
  • Instead, it first interprets the JavaScript using Ignition (V8’s interpreter).
  • Ignition converts the Abstract Syntax Tree (AST) into an intermediate representation called bytecode.

Example: Interpreting JavaScript Code

Consider this JavaScript function:

Loading...

  1. Lexical Analysis & Parsing → The code is tokenized and converted into an AST.
  2. Bytecode Generation → The AST is converted into Ignition bytecode, an intermediate format optimized for quick interpretation.

Example: Bytecode for

Loading...

Loading...

  • LdaNamedProperty a → Load variable

    Loading...

    onto the stack.
  • LdaNamedProperty b → Load variable

    Loading...

    onto the stack.
  • Add → Perform addition.
  • Return → Return the result.

This bytecode is interpreted by Ignition immediately, allowing JavaScript execution to begin quickly.


4. TurboFan: The Optimizing Compiler

While bytecode is fast to execute, it is not as fast as optimized machine code.
If the same function is executed multiple times, V8 considers it hot code and optimizes it using TurboFan.

How TurboFan Works

  1. Profiling Hot Code
    • V8 monitors function calls and identifies frequently executed (hot) functions.
  2. Optimizing the Function
    • If

      Loading...

      is executed many times, TurboFan compiles it into optimized machine code.
  3. Executing the Optimized Code
    • On subsequent calls, V8 runs the optimized machine code version instead of bytecode.

Example: Optimized Machine Code for

Loading...

Loading...

This low-level machine code runs much faster than interpreted bytecode.


5. Deoptimization: When Optimized Code Fails

  • Sometimes, V8 makes incorrect assumptions about the code.
  • If the data type or execution pattern changes, V8 deoptimizes the function back to bytecode.

Example of Deoptimization

Loading...

  • TurboFan assumes

    Loading...

    and

    Loading...

    are always numbers
    .
  • When

    Loading...

    is called, V8 realizes that

    Loading...

    is invalid for strings.
  • Deoptimization occurs, and V8 falls back to bytecode execution.

6. JIT Optimizations in V8

1. Inline Caching

  • Speeds up object property access.
  • Instead of looking up an object property repeatedly, V8 stores the result in a cache.

Example Before Optimization:

Loading...

  • Without inline caching, each

    Loading...

    call requires looking up the "age" property.
  • With inline caching, the first lookup is stored in memory, and subsequent calls skip property lookup, making it faster.

2. Hidden Classes Optimization

  • JavaScript objects are dynamic, which slows down property access.
  • V8 groups similar objects into hidden classes, allowing faster property lookups.

Example Before Optimization:

Loading...

  • Normally, each object has its properties stored dynamically.
  • V8 assigns a hidden class to

    Loading...

    , making future property accesses much faster.

3. Loop Unrolling

  • Optimizes loops by reducing iteration overhead.
  • Instead of executing a loop multiple times, V8 converts it into a single block of code.

Loading...

This reduces loop overhead and speeds up execution.


7. Summary: JIT Compilation in V8

StepDescriptionComponent Involved
1. Ignition InterpreterConverts JavaScript into bytecodeIgnition
2. TurboFan OptimizerCompiles hot code into machine codeTurboFan
3. Inline CachingCaches frequently used propertiesHidden Classes
4. DeoptimizationReverts compiled code if assumptions changeRuntime Profiler

Key Takeaways

  • JIT compilation speeds up JavaScript execution by combining interpretation and compilation.
  • TurboFan optimizes hot code but deoptimizes if assumptions fail.
  • V8 uses techniques like inline caching, hidden classes, and loop unrolling to make JavaScript faster.

By understanding JIT compilation, developers can write high-performance JavaScript code that takes advantage of V8’s optimizations.

3. TypeScript Execution: Transpiration & Compilation

3.1 TypeScript Compilation Process: How TypeScript is Transformed into JavaScript

Unlike JavaScript, which is interpreted and Just-In-Time (JIT) compiled by the V8 engine, TypeScript must be compiled into JavaScript before execution. This is because browsers and JavaScript runtimes like Node.js do not understand TypeScript directly.

TypeScript compilation is handled by the TypeScript Compiler (tsc), which performs several tasks, including:

  • Type checking (ensuring correct type usage)
  • Transpilation (converting TypeScript into JavaScript)
  • Code optimization (removing unnecessary type information)
  • Down-level Compilation (translating modern JavaScript features to older versions)

This section will explore the step-by-step compilation process of TypeScript and explain how it transforms into executable JavaScript.


1. TypeScript Compilation Overview

The TypeScript compilation process consists of three main phases:

StepDescriptionComponent Responsible
Step 1: Type CheckingChecks for type errorsTypeScript Compiler (tsc)
Step 2: TranspilationConverts TypeScript into JavaScriptTypeScript Compiler (tsc)
Step 3: ExecutionJavaScript runs in the V8 engineBrowser / Node.js

TypeScript compilation can be triggered by running the following:

Loading...

This produces a

Loading...

file that can be executed in JavaScript environments.


2. Step 1: Type Checking

What is Type Checking?

TypeScript’s key feature is static typing, which checks for type errors at compile time rather than runtime.

Example: Type Checking in TypeScript

Loading...

  • Before compilation: TypeScript checks that

    Loading...

    should be a

    Loading...

    , but a

    Loading...

    was provided.
  • If a type mismatch is found,

    Loading...

    stops execution and throws an error.

Why Type Checking Matters

  • Prevents runtime errors by catching issues early.
  • Improves code maintainability by enforcing correct type usage.
  • Enables better tooling support with IDEs (e.g., IntelliSense in VS Code).

What Happens Internally?

The TypeScript compiler:

  1. Parses the TypeScript code into an Abstract Syntax Tree (AST).
  2. Checks each variable, function, and return type against its declared types.
  3. If a mismatch is found, compilation fails with an error message.

However, TypeScript does not stop JavaScript execution—it only provides warnings at compile time. The generated JavaScript can still run in a browser or Node.js even if type errors exist.


3. Step 2: Transpilation (TypeScript to JavaScript Conversion)

Once the type-checking phase succeeds, the TypeScript compiler converts the TypeScript code into JavaScript.

How Does Transpiration Work?

  1. Removes all TypeScript-specific syntax (types, interfaces, enums, generics).
  2. Converts modern JavaScript features to older versions (if needed).
  3. Generates clean JavaScript code that is compatible with the chosen ECMAScript target.

Example: TypeScript to JavaScript transpilation

TypeScript Code (

Loading...

)

Loading...

Compiled JavaScript (

Loading...

)

Loading...

  • Type annotations (

    Loading...

    ) are removed
    because JavaScript does not support them.
  • Template literals (

    Loading...

    ) may be downgraded
    if targeting older JavaScript versions.

Configuring Transpilation

Developers can configure the output JavaScript version in the

Loading...

file:

Loading...

Supported targets:

  • ES3 (Oldest, compatible with IE6)
  • ES5 (Compatible with modern browsers)
  • ES6+ (ES2015 - ES2023) (Supports latest features)

4. Step 3: JavaScript Execution

After TypeScript is transpiled into JavaScript, the generated JavaScript file is executed in a browser or Node.js.

How JavaScript is Executed

  • Browser Execution: The JavaScript file is loaded via

    Loading...

    in an HTML file:

Loading...

The browser’s JavaScript engine (V8, SpiderMonkey, JavaScriptCore) parses and runs the script.

  • Node.js Execution: The JavaScript file is run using:

Loading...

Node.js uses the V8 engine to execute the JavaScript.

Example: Running TypeScript in Node.js

  1. Write TypeScript (

    Loading...

    ):

Loading...

  1. Compile to JavaScript:

Loading...

Generates

Loading...

:

Loading...

  1. Execute in Node.js:

Loading...

Output:

Loading...


5. TypeScript Compilation vs JavaScript Execution

FeatureTypeScript CompilationJavaScript Execution
When it occursBefore running the codeAt runtime
Errors detectedCompile-time (static typing)Runtime (dynamic typing)
Performance impactSlower (compilation step needed)Faster startup
Code outputProduces JavaScriptExecutes JavaScript

Key Takeaways

  • TypeScript must be compiled before execution.
  • Type errors are caught at compile time, not runtime.
  • The TypeScript compiler (tsc) removes types and generates JavaScript.
  • JavaScript runs in the browser or Node.js after Compilation.

6. TypeScript Compiler (tsc) Options

The

Loading...

compiler provides many configuration options to customize the compilation process.

Example: Using

Loading...

A tsconfig.json file is used to configure TypeScript compilation:

Loading...

Key Compiler Options

OptionDescription

Loading...

ECMAScript version for output JS

Loading...

Enables strict type checking

Loading...

Specifies output folder for compiled JS

Loading...

Determines module system (

Loading...

,

Loading...

)

To compile a project using

Loading...

:

Loading...

This compiles all

Loading...

files based on the settings in

Loading...

.


7. Summary: How TypeScript is Compiled

StepProcessComponent Responsible
1. Type CheckingEnsures correct typesTypeScript Compiler (

Loading...

)
2. TranspirationConverts TypeScript into JavaScriptTypeScript Compiler (

Loading...

)
3. ExecutionRuns JavaScript in the browser or Node.jsJavaScript Engine (V8, etc.)

  • TypeScript enhances JavaScript with type safety but requires compilation before execution.
  • The TypeScript Compiler (

    Loading...

    ) transforms TypeScript into clean JavaScript
    .
  • Understanding the TypeScript compilation process helps developers write efficient, scalable code.

3.2 JavaScript vs. TypeScript Execution: Understanding the Differences

Both JavaScript and TypeScript are widely used in modern web development, but they differ significantly in how they are executed and processed.

  • JavaScript is executed directly by the browser or Node.js using a Just-In-Time (JIT) compilation approach.
  • TypeScript must first be compiled (or transpiled) into JavaScript before execution.

In this section, we will compare JavaScript and TypeScript execution step by step, exploring compilation, type checking, execution speed, debugging, and runtime behavior.


1. The Core Difference: Compilation vs. Interpretation

FeatureJavaScript ExecutionTypeScript Execution
Compilation Required?No, executed directly by the JavaScript engineYes, TypeScript is compiled into JavaScript before execution
Type CheckingNo type checking; errors appear at runtimeStatically typed; type errors caught at compile-time
Execution SpeedFaster (no pre-compilation step)Slightly slower (requires compilation first)
Error DetectionErrors appear at runtimeErrors detected before execution
Code OptimizationOptimized dynamically by the JavaScript engine (JIT compilation)Optimization depends on the compiled JavaScript

Conclusion:

  • JavaScript starts executing immediately because it is interpreted and compiled Just-In-Time.
  • TypeScript first compiles into JavaScript before execution, adding a step but improving reliability.

2. How JavaScript is Executed

JavaScript execution follows these steps:

  1. Parsing:
    • The JavaScript engine scans the code and converts it into an Abstract Syntax Tree (AST).
  2. Compilation:
    • The JIT Compiler in engines like V8 compiles JavaScript into bytecode.
  3. Execution:
    • The JavaScript engine executes the bytecode, optimizing frequently executed code into machine code.

Example: JavaScript execution

Loading...

  1. The browser or Node.js reads the code and parses it into an AST.
  2. The JIT compiler compiles the function into bytecode.
  3. If

    Loading...

    is called multiple times, the function is optimized into machine code.

JavaScript runs immediately without any pre-processing.


3. How TypeScript is Executed

Unlike JavaScript, TypeScript cannot run directly in a browser or Node.js. It must be compiled into JavaScript first.

TypeScript Compilation Process

  1. Type Checking
    • The TypeScript compiler (

      Loading...

      ) checks for type errors.
  2. Transpilation
    • The TypeScript code is converted into JavaScript (removing type annotations).
  3. JavaScript Execution
    • The generated JavaScript is executed in a browser or Node.js.

Example: TypeScript execution

TypeScript Code (

Loading...

)

Loading...

Compilation Process

Loading...

Error Output:

Loading...

Since there is a type mismatch, TypeScript does not generate JavaScript.

Correct TypeScript Code

Loading...

Generated JavaScript (

Loading...

)

Loading...

  • Type annotations (

    Loading...

    ) are removed
    .
  • Standard JavaScript remains unchanged.

The generated

Loading...

is executed in the JavaScript engine like a standard JavaScript file.


4. Comparing Type Checking and Error Handling

FeatureJavaScriptTypeScript
Type CheckingNo type safety; type errors appear at runtimeStatically typed; errors detected before execution
Error HandlingErrors appear while running the codeErrors appear at compilation, preventing execution
Code SafetyProne to runtime errorsPrevents many errors before execution
FlexibilityHighly flexible (dynamically typed)Strict type rules

Example: Type Errors in JavaScript vs. TypeScript

JavaScript Code (No Type Checking)

Loading...

  • JavaScript does not prevent invalid operations.
  • The error is not caught until runtime, potentially crashing the program.

TypeScript Code (With Type Checking)

Loading...

  • TypeScript prevents execution because

    Loading...

    is not a number.
  • Error appears at compile-time, reducing runtime issues.

5. Execution Speed Comparison

FeatureJavaScript ExecutionTypeScript Execution
Startup SpeedFaster (no compilation)Slower (requires compilation first)
Runtime PerformanceOptimized by JIT CompilerSame as JavaScript after compilation
Code OptimizationDynamic optimization by the engineDepends on generated JavaScript
Error DetectionErrors appear while runningErrors are caught before execution

Which Is Faster?

  • JavaScript executes immediately without compilation, making it faster at startup.
  • TypeScript must be compiled first, but after compilation, it runs at the same speed as JavaScript.
  • The V8 engine optimizes JavaScript dynamically, meaning both JavaScript and TypeScript have the same performance at runtime.

6. Debugging: JavaScript vs. TypeScript

FeatureJavaScript DebuggingTypeScript Debugging
Error DetectionErrors appear at runtimeErrors caught at compile-time
Stack TracesJavaScript stack tracesCan be harder to trace due to compiled output
Debugging ToolsBrowser Developer Tools, VS Code DebuggerRequires Source Maps for debugging compiled JavaScript
Error PreventionNo safeguardsPrevents many errors before execution

Using Source Maps in TypeScript Debugging

Since TypeScript is compiled into JavaScript, debugging the compiled file can be difficult.
To debug TypeScript code directly, source maps are used:

  1. Enable Source Maps in

    Loading...

Loading...

  1. Compile with

    Loading...

Loading...

  1. Debug in Chrome or VS Code, mapping errors back to TypeScript.

7. Final Comparison: JavaScript vs. TypeScript Execution

FeatureJavaScript ExecutionTypeScript Execution
Compilation StepNo compilation requiredMust compile into JavaScript first
Type SafetyNo type checkingStatically typed (errors caught early)
Runtime PerformanceFast (JIT compiled)Same as JavaScript after compilation
DebuggingDirect debuggingRequires source maps for accurate debugging
Error HandlingErrors appear at runtimeErrors appear before execution

Key Takeaways

  • JavaScript runs immediately without compilation.
  • TypeScript needs compilation but catches errors earlier.
  • After compilation, TypeScript runs exactly like JavaScript.
  • Debugging TypeScript requires source maps, while JavaScript debugging is more straightforward.

Which One to Use?

  • Use JavaScript when quick prototyping or writing small scripts.
  • Use TypeScript for large applications where type safety improves maintainability.

By understanding these differences, developers can choose the right tool for their project and write more efficient, bug-free code.

4. JavaScript Optimization in the Browser: How Modern JavaScript Engines Improve Performance

JavaScript is executed dynamically by the browser, making Optimization crucial for performance. Modern JavaScript engines, such as V8 (Chrome), SpiderMonkey (Firefox), and JavaScriptCore (Safari), use advanced techniques to make JavaScript run faster. These optimizations happen behind the scenes but understanding them allows developers to write more efficient code.

This section explores how JavaScript is optimized in the browser, covering Just-In-Time (JIT) compilation, inline caching, hidden classes, garbage collection, and event loop optimizations.


1. The Role of the JavaScript Engine in Optimization

Each browser has its own JavaScript engine that compiles, optimizes, and executes JavaScript code efficiently. The most widely used engines include:

  • V8 (Google Chrome, Edge, Node.js)
  • SpiderMonkey (Mozilla Firefox)
  • JavaScriptCore (Nitro) (Safari)

These engines optimize JavaScript performance using Just-In-Time (JIT) compilation, caching, and garbage collection techniques.


2. Just-In-Time (JIT) Compilation

Unlike traditional interpreted languages, JavaScript engines compile JavaScript into machine code just in time (as the program runs). This hybrid approach speeds up execution.

How JIT Compilation Optimizes JavaScript

  1. Initial Interpretation: The Ignition Interpreter in V8 quickly converts JavaScript into bytecode.
  2. Hot Code Detection: The engine profiles the code and marks frequently executed functions as hot.
  3. Optimized Machine Code Generation: The TurboFan Optimizing Compiler compiles hot code into high-performance machine code.
  4. Deoptimization (if needed): If assumptions change (e.g., variable types change), the function is deoptimized back to bytecode.

Example of JIT Optimization

Loading...

  • The first call is interpreted.
  • The second call compiles the function into optimized machine code.
  • Future calls use the faster optimized version.

Why JIT Compilation Matters

  • Speeds up frequently used functions
  • Eliminates redundant operations
  • Reduces execution overhead compared to pure interpretation

3. Inline Caching (Faster Property Access)

Inline caching is an optimization technique used in JavaScript engines to speed up property lookups in objects.

How Inline Caching Works

  1. The first time a property is accessed, JavaScript performs a normal lookup.
  2. The lookup result is cached for future use.
  3. If the same property is reaccessed, the cached result eliminates the need for a new lookup.

Example Before Optimization

Loading...

  • Without inline caching, each

    Loading...

    access requires a property lookup.

Example After Optimization (Inline Caching)

Loading...

Results:

  • The first lookup stores the location of

    Loading...

    in memory
    .
  • Future lookups skip property searches, making execution much faster.

Why Inline Caching Matters

  • Reduces the overhead of object property lookups.
  • Improves performance when accessing the same property multiple times.

4. Hidden Classes and Property Optimization

JavaScript objects are dynamic, meaning their properties can change at runtime. This makes them harder to optimize compared to statically typed languages like C++.

How Hidden Classes Work

JavaScript engines assign hidden classes to objects to optimize property access.

Example Before Optimization (No Hidden Classes)

Loading...

  • Without hidden classes, each object stores properties separately, making lookups slow.

Example After Optimization (Using Hidden Classes)

Loading...

  • V8 creates a hidden class for

    Loading...

    , allowing faster property access.
  • If properties are added dynamically, the class structure changes, potentially causing deoptimization.

Why Hidden Classes Matter

  • Optimizes object property access.
  • Ensures consistent property order for faster lookups.

5. Garbage Collection (Memory Management)

JavaScript engines use automatic memory management to remove unused objects without manual intervention.

How Garbage Collection Works

  1. Mark-and-Sweep Algorithm:
    • The engine marks objects that are still in use.
    • Unreachable objects are removed.
  2. Generational Garbage Collection:
    • New objects are allocated in the "young" generation.
    • If they persist long enough, they move to the "old" generation.
    • Old objects are cleaned up less frequently to avoid performance slowdowns.

Example: Memory Leak Prevention

Loading...

  • The

    Loading...

    object is deleted automatically
    , freeing up memory.

Why Garbage Collection Matters

  • Prevents memory leaks in long-running applications.
  • Ensures efficient memory usage by reclaiming unused memory.

6. Event Loop and Microtask Queue Optimization

The Event Loop ensures that JavaScript remains non-blocking and asynchronous.

How JavaScript Optimizes Asynchronous Tasks

  • Microtasks (Promises, async/await) run before normal tasks.
  • Long-running synchronous tasks are minimized to keep the UI responsive.

Example: Event Loop Optimization

Loading...

Execution Order:

  1. Loading...

    is logged.
  2. Loading...

    is logged.
  3. Microtask (Promise) runs before timeout.
  4. Loading...

    is logged.
  5. Loading...

    is logged.

Why This Optimization Matters

  • Ensures UI responsiveness by prioritizing microtasks over macrotasks.
  • Prevents rendering jank by efficiently handling asynchronous operations.

7. Summary of JavaScript Browser Optimizations

Optimization TechniqueDescriptionPerformance Benefit
JIT CompilationCompiles JavaScript to machine code dynamicallyFaster execution of hot code
Inline CachingCaches frequently accessed propertiesReduces object lookup times
Hidden ClassesOptimizes object property access by using consistent structuresFaster property access
Garbage CollectionAutomatically removes unused objectsPrevents memory leaks
Event Loop OptimizationPrioritizes microtasks for smoother executionBetter UI responsiveness

Final Thoughts

Modern JavaScript engines apply multiple layers of Optimization to ensure fast and efficient execution. By understanding these techniques, developers can:

  • Write more efficient JavaScript code.
  • Avoid performance pitfalls that trigger deoptimization.
  • Leverage browser optimizations to improve responsiveness.

By structuring code with these optimizations in mind, JavaScript applications can achieve blazing-fast execution speeds in the browser.

** Book Recommendation:

Join Our Discord Community Unleash your potential, join a vibrant community of like-minded learners, and let's shape the future of programming together. Click here to join us on Discord.

For Consulting and Mentorship, feel free to contact slavo.io

©2026. All rights reserved. Designed by Prototype.NEXT

slavo.io software development - Consultingslavo.io software development - Consulting slavo.io software development - Consulting