The Architecture of Web Browsers
Hey Everyone,
Today we’ll be talking about
How Web Browsers Work
The Architecture and how the different components work together
How the Rendering Engine works
Plus, a couple awesome tech snippets on
Extreme HTTP Performance Tuning - Marc Richards managed to squeeze out 1.2 million requests/second from a 4 vCPU AWS EC2 instance. Here’s how he did it.
50 Design Tips To Improve User Interfaces - A great PDF with 50 actionable design tips on how to develop better looking UIs
An Interactive Guide to the Discrete Fourier Transform - A great introduction to the Discrete Fourier Transform.
We have a solution to our last coding interview question on arrays, plus a new question from Facebook.
Quastor Daily is a free Software Engineering newsletter sends out FAANG Interview questions (with detailed solutions), Technical Deep Dives and summaries of Engineering Blog Posts.
How Web Browsers Work
The following diagram illustrates the parts of a web browser and how they interact with each other.
User Interface
This is the user interface for the browser. It includes the Address Bar, back button, Bookmarking options, Refresh button, etc.
The browser’s user interface is not specified in any formal specification, but comes from practices shaped over decades of experience (and browsers copying each other).
As a result, all browsers have UIs that are extremely similar to each other.
The Browser Engine
The browser engine marshals actions between the browser’s user interface and the browser’s rendering engine.
When you type in a new website and press the enter key, the browser UI will tell the browser engine, which will then communicate with the rendering engine.
The Rendering Engine
The rendering engine is responsible for displaying the requested content.
The rendering engine will start by getting the contents of the requested document from the networking layer.
It takes in the HTML code and parses it to create the DOM (Document Object Model) tree.
The rendering engine will then parse the CSS to build the CSSOM (CSS Object Model). It’s like the DOM, but for the CSS rather than the HTML.
While the CSS is being parsed and the CSSOM is being created, the browser is downloading other assets through the Network Layer like JavaScript files.
The rendering engine communicates with the JavaScript engine to execute the JavaScript code and manipulate the DOM and CSSOM.
The rendering engine then takes the DOM and the CSSOM and combines them to create the Render tree.
The rendering engine then uses the UI backend for laying out the website on the screen and finally painting the pixels to the screen.
The entire process that the rendering engine goes through is called the Critical Rendering Path.
Examples of rendering engine include
Safari - WebKit Rendering Engine
FireFox - Gecko Rendering Engine
Here’s a more detailed look at the flow for WebKit
Networking Layer
The Networking Layer is responsible for making network calls to fetch resources.
It imposes the right connection limits, formats requests, deals with proxies, caching, and much more.
You can read more about the Networking Layer here.
JavaScript Engine
The JavaScript Engine is used to parse and execute JavaScript code on the DOM or CSSOM. The JavaScript code is provided by the web server, or it can be provided by the web browser (browser extensions or features of the browser like automatic ad-blocking).
Early browsers used JavaScript interpreters, but modern JavaScript engines use Just-In-Time compilation for improved performance.
Examples of JavaScript Engine include
Chrome - V8 JavaScript Engine
Safari - JavaScriptCore
FireFox - SpiderMonkey Engine
UI Backend
This layer is responsible for drawing the basic widgets like select or input boxes and windows. Underneath it uses operating system UI methods.
The rendering engine uses the UI backend layer during the layout and painting stages to display the web page on the browser.
Data Storage
The browser needs to save data locally (cookies, cache, etc.) so the Data Storage component handles this part.
Modern browsers also support storage mechanisms like localStorage, IndexedDB, and FileSystem. This is a great article on all the options for browser-side storage.
We’ve just covered the surface level here, if you’d like to dig deeper on how the HTML and CSS parsers work as well as how the JavaScript Engine works, read the full blog post here.
Quastor Daily is a free Software Engineering newsletter sends out FAANG Interview questions (with detailed solutions), Technical Deep Dives and summaries of Engineering Blog Posts.
Tech Snippets
An Interactive Guide to the Discrete Fourier Transform - The Discrete Fourier Transform is used widely in algorithms. Data compression, cryptography, machine learning, etc. all depend on DFTs.
This is a great article that provides intuitive visualizations and a great explanation on how the Discrete Fourier Transform works.
50 Design Tips to Improve User Interfaces - If you’re like me, your UIs look like they were designed by a 6 year old. This is a great PDF with 50 design tips on how to develop better looking UIs
Extreme HTTP Performance Tuning - Marc Richards managed to squeeze out 1.2 million JSON API requests per second from an 4 vCPU AWS EC2 instance.
He breaks down how he was able to do it in this detailed blog post.
Interview Question
You are given an integer n.
Return the number of structurally unique binary search trees that have n nodes of unique values from 1 to n.
We’ll send a detailed solution tomorrow, so make sure you move our emails to primary, so you don’t miss them!
Gmail users—move us to your primary inbox
On your phone? Hit the 3 dots at the top right corner, click "Move to" then "Primary"
On desktop? Back out of this email then drag and drop this email into the "Primary" tab near the top left of your screen
Apple mail users—tap on our email address at the top of this email (next to "From:" on mobile) and click “Add to VIPs”
Previous Solution
As a reminder, here’s our last question
You are given an array of integers sorted in non-decreasing order.
Write a function that removes any duplicates in the array so that each element appears only once.
Your function must use constant space, so your space complexity must be O(1).
The function should return k, where k is the number of unique items in the array. The first k items in the array should be the unique integers in sorted order from least to greatest.
The elements in the array after the first k elements can be whatever you choose.
Your function should run in O(n) or better.
Here’s the question in LeetCode
Solution
The array is sorted in non-decreasing order.
Because of this, all duplicates will be right next to each other.
We can take advantage of this by using a fast and slow pointer. Both pointers will start at index 1.
The fast pointer will iterate through the array and check if a number is unique. We can check if a number is unique by seeing if it’s the same as the number before it.
If the number is unique, then we will write it to the index where the slow pointer is pointing. Then we’ll increment the fast and slow pointers.
If the number is not unique, then we will just increment the fast pointer.
When the fast pointer reaches the end of the array, then we’ll end our loop.
All the integers in our array up to the slow pointer will be unique and sorted.
Therefore, we can return our slow pointer as k.
Here’s the Python 3 code.
What’s the time and space complexity of our solution? Reply back with your answer and we’ll tell you if you’re right/wrong.