• Inside Look at Modern Web Browser (Part 2)
  • Originally written by Mariko Kosaka
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: CoolRice
  • Proofread by ThomasWhyne, tian-li

What happens when you navigate

This is the second in a four-part blog series on the inner workings of Chrome. In the last article, we looked at how different processes and threads handle different parts of the browser. In this article, we’ll take a closer look at how each process and thread communicates to present the site.

Let’s look at a simple use case for web browsing: You type a URL into a browser, and the browser retrieves data from the Internet and displays a page. In this article, we will focus on the part where the user requests that the site and the browser prepare to render the page — that is, navigation.

It starts with a browser process

Figure 1: The top is the browser UI, and the bottom is the browser process diagram with the UI, network, and storage threads

As we discussed in Part 1: CPU, GPU, Memory, and Multi-process Architecture, everything outside the TAB is handled by the browser process. Browser processes have many threads, such as the UI thread that draws browser buttons and input fields, the network thread that processes the network stack to fetch data from the Internet, the storage thread that controls file access, and so on. When you type a URL into the address bar, your input is processed by the BROWSER process’s UI thread.

A simple navigation

Step 1: Process the input

When the user starts typing into the address bar, the first thing the UI thread asks is “Is this a search query or a URL address?” . In Chrome, the address bar is also a search input bar, so the UI thread has to parse and decide whether to send your request to the search engine or to the site you are requesting.

Figure 1: The UI thread asks if the input is a search query or a URL address

Step 2: Start navigation

When the user presses The Enter key, the UI thread enables a network call to retrieve the site content. The loading animation is displayed in the corner of the TAB, and the network thread passes through the appropriate protocols, such as DNS look-ups and establishing TLS connections for the request.

Figure 2: The UI thread tells the network thread to navigate to mysite.com

At this point, the network thread might receive a server redirect header like HTTP 301. In this case, the network thread tells the UI thread that the server is requesting a redirect. Then, another URL request is initiated.

Step 3: Read the response

Figure 3: The response header containing the Content-Type and the payload as the actual data

Once it starts receiving payload, the network thread looks at the first few bytes of the data stream if necessary. The content-Type field of the response message declares the Type of the data, but it can be lost or incorrect, so MIME Type sniffing is used to solve this problem. This is the “thorny issue” commented on in the source code. You can read the comments and see how different browsers match content-type and payload.

If the response is an HTML file, the next step is to pass the data to the renderer, but if it is a zipped file or something else, it means it is a download request and therefore needs to pass the data to the download manager.

Figure 4: A network thread asks if the response data is HTML from a secure web site

SafeBrowsing is also performed at this point. If the domain name and response data appear to match a known malicious site, the network thread displays a warning page. In addition, a Cross Origin Read Blocking (CORB) check occurs to ensure that sensitive cross-domain data is not passed to the renderer process.

Step 4: Find the renderer process

Once all the checks have been performed and the network thread is sure that the browser will navigate to the requested site, the network thread tells the UI thread that all the data is ready. The UI thread looks for the renderer process to start rendering the Web page.

Figure 5: The network thread tells the UI thread to find the renderer

Because network requests can take hundreds of milliseconds to get a response back, an optimization measure can be applied. In step 2, when the UI thread is sending a URL request to the network thread, it already knows which site they will navigate to. In parallel with the network request, the UI thread attempts to actively find or start a rendering process. This way, if everything goes as expected, the rendering process is already on standby when the network thread receives the data. If the navigation is redirected across domains, the standby process may not be used, in which case another process may be used.

Step 5: Submit the navigation

Now that the data and renderer are ready, the browser process sends an IPC (inter-process communication) to the renderer process to submit the navigation. It also passes data streams, so the renderer can keep receiving HTML data. Once the browser process receives an acknowledgement that the renderer has committed, the navigation is complete and the document load parsing begins.

At this point, the address bar has been updated, and the security indicator and site Settings UI reflect the site information for the new page. The TAB’s session history is updated, so the forward/back buttons go to the site you just navigated. When you close tabs or Windows, the session history is saved on hard disk to optimize TAB/Session restoration.

Figure 6: IPC between the browser and the renderer, requesting a rendered page.

Additional steps: initial loading completed

Once the navigation is committed, the rendering process starts loading the resources and rendering the page. We’ll explain in detail what happens at this stage in the next article. Once the render process has rendered “finished”. It sends an IPC back to the browser process (this happens after all frame onload events on the page have been fired and executed). At this point, the UI thread stops the loading animation on the TAB page.

I say “over” because client-side JavaScript can still load additional resources and render new views after that point.

Figure 7: The renderer sends IPC to the browser process notification page “loaded”

Navigate to another site

Easy navigation is complete! But what happens when the user enters another URL in the address bar? Well, the browser process performs the same steps to navigate to a different site. But before it does this, it checks whether the currently rendered site cares about the beforeUnload event.

Beforeunload can create “Leave this site?” when you try to navigate off or close tabs. Warning. Everything inside the TAB, including your JavaScript code, is handled by the renderer process, so when a new navigation request comes in, the browser process must check with the current renderer process.

Note: Do not add unconditional beforeUnload handlers. It creates more latency because the handler needs to be executed before the navigation begins. This event handler should be added only when needed, such as if users need to be warned that they may lose the data they entered on the page.

Figure 8: The browser process sends IPC to the renderer process telling it to navigate to another site

If the renderer has started navigation (like the user clicking on a link or the client JavaScript running window.location = “https://newsite.com”), the renderer checks the beforeUnload event handler first. It then performs the same steps as the browser handles launch navigation. The only difference is that the navigation request is sent by the renderer process to the browser process.

When the newly navigated site is different from the currently rendered site, a separate renderer process is called to handle the new navigation while holding the current renderer process to handle events like unload. For more information, see the Page Lifecycle Overview and how to declare cycle API hook events using pages.

Figure 9:2 IPC (from the browser process to the new renderer) tells the render page and tells the old renderer to unload

If there is a Service Worker

A recent change to the navigation process is the introduction of the Service worker. A service worker is a way to write network agents in your application code; Allows Web developers more control over locally cached content and when to fetch new data from the network. If the service worker is set up to load pages from the cache, there is no need to request data from the network.

The important part to remember is that a Service Worker is JavaScript code that runs in the renderer process. But how does the browser process know that the site has a service worker when a navigation request comes in?

Figure 10: The network thread in the browser process looks up the Service worker scope

When registering a service worker, keep The scope of The service worker as a reference (you can read more about scope in The Service Worker Lifecycle article). When a navigation occurs, the network thread checks the domain name with the registered service worker scope. If a service worker has been registered for the URL, the UI thread finds a render thread to execute the service worker code. The service worker may load data from the cache without having to request data from the network, or it may request new resources from the network.

Figure 11: The UI thread in the browser starts the render process to process the Service workers; The worker thread in the renderer process then requests the data from the network

Navigation preloading

As you can see, if the service worker finally decides to request data from the network, the round-trip between the browser process and the renderer process can cause delays. Navigation preloading is a mechanism to speed up this process by loading resources in parallel with service worker startup. It marks these requests with a header, allowing the server to decide to send different content for these requests; For example, update only the data and not the full document.

Figure 12: The UI thread in the browser process starts the renderer process to process the service worker while starting the network request in parallel

conclusion

In this article, we looked at what happens during navigation and how your Web application code, such as response headers and client-side JavaScript, interacts with the browser. Understanding the steps a browser takes to get data over the network makes it easier to understand why apis such as navigation preloading were developed. In the next article, we’ll delve into how browsers parse HTML/CSS/JavaScript to render pages.

Did you enjoy this article? If you have any questions or suggestions for future articles, feel free to leave them in the comments section below or on Twitter @kosamari.

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.