How Browsers Make Websites Come to Life

Amin Partovi
Geek Culture
Published in
12 min readMar 5, 2023

As a web developer, you may be asked a series of fundamental questions about how a web page is displayed on a screen during a technical interview. Here are 10 of the most common questions:

1. How does the browser work?

2. What is the Critical Rendering Path, and why is it important?

3. What is the order of downloading and executing resources on a web page?

4. Can JavaScript files pause the parsing of HTML?

5. What is a rendering engine and how does it affect the display of a web page?

6. What is the process of displaying a web page on the screen?

7. What is a JavaScript engine and its role in web development?

8. How does a web page become interactive?

9. How does JIT compilation work?

10. Can you name the ways JIT compiler optimizes the JavaScript execution?

In this article, we will delve into the answers to these questions and provide an overview of how the browser works.

photo by Deepanker Verma

How web browser retrieve page resources

When you enter a URL in a web browser, the first step is for the browser to determine the IP address associated with that URL. This allows the browser to establish a connection and retrieve the web page. The browser checks its cache to see if it has recently resolved the IP address for the URL, and if found, it will use that information. If the IP address is not in the cache, the browser will perform a DNS resolution to find the IP address of the server associated with the URL. This process may require several requests between servers, but it typically takes just a few milliseconds.

Once the IP address is determined, the browser creates an HTTP request to the IP address and retrieves the web page resources. This transmission is established through a 7-layer model known as Open System Interconnection, which defines how information is transferred between software applications in different computers. The data is transmitted over the internet in packets with varying sizes, depending on the network protocols being used.

Critical Rendering Path

The Critical Rendering Path is the sequence of steps the browser goes through to convert the HTML, CSS, and JavaScript into pixels on the screen. Optimizing the critical render path improves render performance.

The process of downloading and executing resources on a web page is determined by various factors such as the resource type, the sequence in which they are specified in the HTML code, and network conditions. The browser first begins by downloading the HTML code of the web page.

How the rendering engine works

The process starts with the rendering engine taking over, reading and parsing the HTML content line by line. The parsing process starts with the first chunk of data and the first tag being <html>. Images and CSS files are considered non-blocking resources and do not prevent the rendering engine from parsing the HTML code. However, script tags without the “defer” or “async” attribute will block the parsing process. HTML parsing is established through two processes, tokenization and tree construction. When the parser occupies the main thread, the preload scanner requests high priority resources like CSS, JavaScript, and web fonts.

figure 1- The most commonly used browsers and their rendering engines

The rendering engine workflow is shown in figure 2. The lexer (also known as a lexical analyzer or scanner) is a component that breaks down the HTML code into a series of tokens or elements. A token is a basic unit of the HTML code, such as a tag, attribute, or text content. The lexer’s job is to identify these tokens and pass them along to the parser (step 1).

how the browser rendering engine works
figure 2- how the browser rendering engine works

A parser, on the other hand, is a component that takes the tokens produced by the lexer and uses them to create a hierarchical representation of the HTML elements and their relationships to one another. This representation is known as the Document Object Model (DOM) tree. The parser takes the tokens from the lexer and uses them to build the DOM tree, which is a tree-like structure that mirrors the structure of the HTML code (step2).

The process of parsing CSS is similar to the process of parsing HTML for a rendering engine. Just as the HTML parser breaks down the HTML code into tokens, creating a Document Object Model (DOM) tree to represent the elements and their relationships, the CSS parser takes the CSS code and creates a CSS Object Model (CSSOM) tree to represent the styles and layout information for the web page.

The process of combining the DOM and CSSOM involves the following steps:

1. Style Resolution: The CSSOM information is applied to the elements in the DOM tree to determine the styles that apply to each element. The rendering engine resolves any conflicting styles and computes the final style information for each element (step 3).

2. Layout: The rendering engine uses the final style information to calculate the layout of the web page, including the size and position of each element (step 4).

3. Construction of the Render Tree: The render tree is created by merging the information in the DOM tree and the CSSOM tree. The render tree only includes the elements that are actually visible on the screen and takes into account the styles specified in the CSS (step 5).

4. Painting: The rendering engine uses the information in the render tree to paint the visual representation of the web page onto the screen. The rendering engine converts each box calculated in the layout phase to actual pixels on the screen (step 6).

Render blocking behavior of JavaScript

JavaScript is a programming language that can be used to add interactivity and dynamic behavior to web pages. To include JavaScript code in an HTML file, there are various ways to do so. One way is to place the code in a script tag within the head or body of the HTML document. Alternatively, the code can be placed in a separate JavaScript file that is linked to the HTML document. When the browser comes across a script tag or a linked JavaScript file, it temporarily stops parsing the HTML in order to fetch and execute the JavaScript code. This is because JavaScript can modify the content and structure of the HTML page, and the browser needs to wait for the JavaScript code to be executed before it can determine the final layout of the page. This behavior is known as “render-blocking.”

Fortunately, there are techniques available that can minimize the impact of render-blocking JavaScript. One such technique is to use the async or defer attribute on the script tag to instruct the browser on how to handle the script. Using the async attribute will allow the script to be loaded and executed asynchronously, while the rest of the page continues to load. On the other hand, using the defer attribute will defer the execution of the script until the page has finished parsing.

How the JavaScript engine works

It’s important to note that the JavaScript engine is responsible for executing JavaScript code. Once the JavaScript code is parsed, compiled, and optimized, the engine generates machine code that can be executed directly by the computer’s processor.

JavaScript engines
figure 3- The most commonly used browsers and their JavaScript engines

To understand how the JavaScript engine processes JavaScript code, it is helpful to break down the process into several steps.

Step 1: Tokenization: The first step in parsing a JavaScript file is tokenization, where the source code is split into individual tokens. A token is a sequence of characters that represents a unit of meaning in the code. Tokens can include keywords, identifiers, operators, and literals.

Step 2: Lexical Analysis: The next step in parsing is lexical analysis, where the JavaScript engine groups the tokens into a series of lexemes, which are the smallest units of meaning in the source code. The parser constructs an abstract syntax tree (AST) from the lexemes. The AST is a structured representation of the code that represents the relationships between the various elements of the code, such as variables, functions, and expressions. The AST provides a way to understand the structure of the code and how it will be executed.

Step 3: Bytecode Generation: After parsing JavaScript and creating the AST, it is time to convert the AST to machine-readable code. The abstract syntax tree is then compiled into an intermediate representation called bytecode, which is a series of low-level instructions that represent the operations specified in the source code. The interpreter, such as Ignition for Chrome, is responsible for quickly executing JavaScript code and creates bytecode that is not yet optimized.

Step 4: Compiling: The compiler, such as Turbofan for Chrome, then compiles the JavaScript code into machine code, with the goal of optimizing the code for faster execution. This is done by analyzing the code and applying various optimizations, such as removing unused code, inlining functions, and optimizing the memory access patterns.

Step 5: Execution: The generated code is executed by the engine, which reads each instruction and performs the specified operations. The engine maintains a call stack that keeps track of the current function being executed and the return value of each function.

Step 6: Optimization: the JIT compiler receives feedback about the behavior of the code during execution. This feedback is used to optimize the generated machine code, improving the performance of future executions of the code. The compiler and interpreter receive feedback about the execution of the machine code through various performance monitoring and profiling tools. These tools track and measure various aspects of the code execution, such as the number of instructions executed, the amount of memory used, and the speed of function calls. The compiler uses this information to optimize future executions and improve performance.

how the JavaScript engine works
figure 4- how the JavaScript engine works

Just-In-Time compilation

The technique described above to convert AST to machine readable code is Just-In-Time (JIT) compilation which is used by modern JavaScript engines to improve the performance of JavaScript code execution.

Traditionally, JavaScript code is interpreted at runtime by the JavaScript engine, which means that the engine reads each line of code and executes it one by one. This process can be slow and inefficient for large or complex JavaScript programs.

To improve performance, modern JavaScript engines use a technique called JIT compilation. JIT compilation works by analyzing the code as it is executed and generating machine code on the fly to optimize the code for faster execution.

When the engine encounters a piece of JavaScript code that is executed frequently, it compiles that code into machine code that can be executed directly by the computer’s processor. This allows the engine to execute the code more quickly and efficiently on subsequent runs.

There are different approaches to JIT compilation, but they generally involve three stages:

Interpretation: The engine initially interprets the JavaScript code and generates bytecode, which is a low-level representation of the code.

Profiling: The engine profiles the code as it runs to identify hotspots, which are sections of code that are executed frequently and could benefit from JIT compilation.

Compilation: The engine generates optimized machine code for the hotspots and replaces the interpreted bytecode with the new machine code, allowing the engine to execute the code more quickly in the future.

some ways that JIT compiler optimizes JavaScript execution are:

· Inlining: JIT compiler can analyze the code and replace function calls with the actual code. This reduces function call overhead and improves performance.

· Loop unrolling: JIT compiler can optimize loops by unrolling them, which means executing loop iterations in parallel. This can improve performance by reducing loop overhead.

· Dead code elimination: JIT compiler can identify and remove code that will never be executed. This reduces the size of the code and improves performance.

· Type specialization: JIT compiler can optimize code based on the types of data that are being used. This can improve performance by allowing for more efficient memory access.

· Escape analysis: JIT compiler can analyze the usage of objects in the code and optimize the memory usage accordingly. This can improve performance by reducing the number of object allocations and memory accesses.

Make a web page interactive

The process of creating an interactive web page involves the collaboration of the rendering engine and JavaScript engine in the following manner:

1. Parsing HTML, CSS, and JavaScript: The rendering engine receives the HTML and CSS code and constructs the Document Object Model (DOM) and the Render Tree. If there is any JavaScript code included, the JavaScript engine receives and executes it.

2. Updating the DOM and Render Tree: When the JavaScript code modifies the DOM or styles, the rendering engine updates the Render Tree to reflect the changes.

3. Repainting: The rendering engine paints the affected parts of the web page based on the updated Render Tree.

4. Executing event handlers: When a user interacts with the web page, the JavaScript engine executes the relevant event handlers.

5. Repeat: The cycle repeats as the user continues to interact with the web page, and the JavaScript code updates the DOM and styles, causing the Render Tree and the painted image to be updated accordingly.

In this way, the rendering engine and JavaScript engine work together to create an interactive web page that can respond to user input and dynamically update the content and layout. The process involves a continuous interplay between the two engines, resulting in a seamless user experience.

Conclusion

At the beginning of the article, we posed several questions related to the topic at hand. As we’ve gone through the article, we’ve provided detailed information and explanations that answer these questions. However, it’s important to reiterate these answers briefly for the sake of clarity and to reinforce the key takeaways.

1. How does the browser work?

Answer: The functioning of a browser involves the reception of HTML, CSS, and JavaScript files from the server, which are then parsed and interpreted. The browser’s rendering engine is tasked with parsing and rendering HTML and CSS, while the JavaScript engine is responsible for parsing, executing, and optimizing JavaScript code. The interactive nature of the web page is made possible through the collaborative effort of these two engines.

2. What is the Critical Rendering Path, and why is it important?

Answer: The Critical Rendering Path is the sequence of steps the browser goes through to convert the HTML, CSS, and JavaScript into pixels on the screen. Optimizing the critical render path improves render performance.

3. What is the order of downloading and executing resources on a web page?

Answer When a web page is loaded, the HTML file is downloaded and parsed first. Resources on a web page are downloaded and executed in the order they appear in the HTML code. CSS files and images are not render-blocking, however JavaScript files without “async” and “differ” attribute can pause HTML execution.

4. Can JavaScript files pause the parsing of HTML?

Answer: Yes, JavaScript code can modify HTML structure, so the browser temporarily stops parsing HTML when it encounters a script tag or linked JavaScript file, a behavior called “render-blocking”. To minimize this impact, async or defer attributes can be used on the script tag to load and execute the script asynchronously, or to defer the execution of the script until the page is finished parsing.

5. What is a rendering engine and how does it affect the display of a web page?

Answer: Rendering engine is a program that convert HTML and CSS contents to the pixles on the screen.

6. What is the process of displaying a web page on the screen?

Answer: The rendering engine parses HTML and CSS to construct the DOM and CSSOM, styles the DOM based on CSSOM, layouts the elements, and constructs the render tree, then it paints the render tree on the screen.

7. What is a JavaScript engine and its role in web development?

Answer: A JavaScript engine is a program that executes JavaScript code in a web browser. It parses JavaScript codes and uses a technique named Just-In-Time compilation to execute JavaScript code optimally.

8. How does a web page become interactive?

Answer: To make a web page interactive, the JavaScript code needs to be executed, which enables dynamic changes to the DOM and the ability to respond to user input. The JavaScript engine and the rendering engine must work together to achieve this functionality.

9. How does JIT compilation work?

Answer: JIT compilation analyzes and optimizes code on the fly for faster execution. It works by interpreting JavaScript code and generating bytecode, identifying performance improvement opportunities and replacing the interpreted code with optimized machine code.

10. Can you name the ways JIT compiler optimizes the JavaScript execution?

Answer: Inlining, loop unrolling, dead code elimination, type specialization, escape analysis

if you enjoy the article follow me on LinkedIn

--

--

Amin Partovi
Geek Culture

A passionate developer exploring various technologies. Let's connect to geek out together! Keep coding and stay curious! https://github.com/Amin-Partovi