CPU, process, thread

  • processIs the smallest unit of CPU resource allocation (the smallest unit that can own resources and operate independently)
  • threadThread is the smallest unit of CPU scheduling.
  • differentprocessCan also communicate with each other, but at a higher cost
  • Single threadwithmultithreadingBoth are in the same placeprocessInside the single and many

For the computer, every application is a process, and each application will have a number of functional modules, these functional modules are actually through the sub-process to achieve. We can call this application multi-process for the way the subprocess is extended.

For a browser, the browser is multi-process. For example, if you open multiple tabs in Chrome, each TAB page is an independent process.

Browser architecture

For browsers, a process can have many different threads, or many different processes can have multiple threads communicating through IPC.

For Chrome, the latest architecture looks like this:

What processes are included in the browser

process role
Browser The main process (browser process) that controls the “Chrome” part of the application, including the address bar, bookmarks, and back and forward buttons. It also handles the invisible privileged parts of the Web browser, such as network requests and file access.
Renderer The renderer process that controls the display of any content in the tabs of the site. That’s what we talked aboutBrowser kernel, one render per TAB page
Plugin Plugin process that controls any plug-ins used by the site, such as Flash.
GPU A graphics processing process that processes GPU tasks independently of other processes. It is divided into different processes because the GPU processes requests from multiple applications and draws them on the same surface.

The following image shows different processes pointing to different parts of the browser UI:

What threads are included in the browser kernel (the renderer process)

thread role
GUI rendering thread – Responsible for rendering pages, layout and drawing

– Page requiredredrawandbackflow, the thread will execute

– Mutually exclusive with js engine threads to prevent unexpected rendering results
JS engine thread – Responsible for parsing and executing javascript script programs

– Only one JS engine thread (single thread)

– Mutually exclusive with GUI rendering threads to prevent unexpected rendering results
Event trigger thread – Used to control event loops (mouse clicks, setTimeout, Ajax, etc.)

– When the event meets the trigger condition, the event is placed in the execution queue of the JS engine
Timing trigger thread setIntervalwithsetTimeoutThread where

– Timed tasks are not timed by the JS engine, but by the timed triggering thread

– Notifies the event to trigger the thread after the timer finishes
Asynchronous HTTP request threads – The browser has a separate thread for handling AJAX requests

– Notifies the event trigger thread when the request completes, if there is a callback function

Why is javascript single threaded

As a browser-side scripting language, Javascript’s main task is to handle user interaction, and user interaction is nothing more than responding to some DOM events/add/delete elements in the DOM. If Javascript is designed to be multithreaded, manipulating the DOM inevitably involves competing for resources, leading to unexpected results.

In order to make use of the computing power of multi-core CPU, HTML5 proposes the Web Worker standard, which allows JS scripts to create multiple threads, but the child threads are completely controlled by the main thread and cannot operate DOM. Therefore, this new standard does not change the nature of JS single threads.

Why are GUI rendering threads and JS engine threads mutually exclusive

JS is capable of manipulating the DOM, and if you modify element attributes and render the interface at the same time (i.e., the JS thread and the GUI thread are running at the same time), the renderer thread may get different elements in sequence.

JS engine thread and GUI rendering thread are mutually exclusive. In order to make macro task and DOM task orderly, the browser will start rendering the page after the execution result of one macro task and before the execution of the next macro task.

Macro Tasks --> Render --> Render --> Render...Copy the code

The running mechanism of Event Loop and JS

When the code is executed to setTimeout/setInterval, it is the JS engine thread that notifies the timing trigger thread that a callback event will be triggered after a certain interval. The timing trigger thread, after receiving the message, will put the callback event into the event queue managed by the event trigger thread after a certain period of time.

When the code execution to the XHR/fetch, actually inform asynchronous HTTP requests is JS engine threads, thread sends a network request, and make requests after the completion of the callback event, and asynchronous HTTP requests threads after received the news, will be after the request is successful, the callback event into a thread managed by event is triggered by the event queue.

When our synchronization task is finished, the JS engine thread will ask the event triggering thread whether there is any callback function waiting to be executed in the event queue, if there is, it will be added to the execution stack and handed to the JS engine thread to execute

Enter the URL until the page is loaded and what happens

First, navigation jump

steps role figure
Step1. Process input When you type something into the browser’s address bar,Browser ProcessIn theThe UI threadIt parses the input to determine whether it is a search query or a URL, and then sends it to a search engine or to the requested site.
Step2. Start looking After entering the address bar and pressing enter,Browser ProcessIn theThe network threadWill be carried out inDNS lookups, and to establishThe TLS connection. If you receive a server redirect header (such as HTTP301),The network threadWill request redirection with the serverThe UI threadCommunicate, and then make another URL request.
Step3. Read the response When the request response comes back,The network threadIs on the basis ofContent-TypeDetermine the data type, doneMIME Type sniffingTo determine whether data is missing or incorrect
If the response content is in HTML format, the next step is to pass the data torenderer processIf it is a ZIP file or other file, the data is transferred to the download manager.

That’s where security checks are done, and if the domain and data match a malicious site,The network threadAn alert is issued and a warning page is displayedCORS checkAlso triggered to ensure sensitive data is not passed to the renderer process
Step4. Find the renderer process When all the above checks are complete, the Network Thread is confident that the browser can navigate to the requested page,network threadWill informUI threadThe data is ready,UI threadYou’ll find onerenderer processRender web pages.

Since it takes time for a network request to get a response, there is actually an acceleration scheme. When the UI Thread sends a URL request to the Network Thread, the browser already knows which site to navigate to. The UI Thread searches for and starts a rendering process in parallel. If all goes well, the rendering process will be ready when the Network Thread receives the data, but if it encounters redirection, the prepared rendering process may not be available and a new rendering process will need to be restarted.
Step5. Submit At this point, the data and renderer processes are ready, and the Browser Process follows the Renderer ProcessThe IPC communicationRequest the Renderer process to render the page. Once the Browser Process receives a render confirmation message from the Renderer Process, the navigation Process ends and the page loading Process begins. At this point, the address bar is updated to show the page information for the new page. The History TAB is updated to return to the navigated page using the back key, and this information is stored on the hard disk to make it easier to recover after closing the TAB or window.
Other steps: The first frame is rendered When the Renderer Process finishes rendering (which means that all pages within the page, including all iframes, have triggered onLoad), it sends an IPC signal to the Browser Process, The UI Thread stops showing the TAB spinner. At this point the page is justThe first frame is renderedAfter that, the client can still download additional resources to render the new view.

What happens if the user again puts a different URL in the address bar and navigates to another site?

Browser processes follow the same steps to navigate to different sites. But before doing that, it needs to check whether the currently rendered site has beforeUnload events. Beforeunload can create a “Leave this site?” To alert you when you leave or close the TAB. Everything inside the TAB (including JavaScript code) is handled by the renderer process, so the browser process must check the current renderer process when a new navigation request comes in.

Note: Do not add unconditional beforeunload handlers. It creates more latency because the handler needs to be executed before the navigation begins. You should add this event handler only when necessary, for example, if you need to warn users that they may lose data entered on the page.

If you navigate to a new site, a new Render process is started to handle the rendering of the new page and the old process is left to handle events like Unload.

Here are two IPC’s from the browser process to the new renderer process, telling the render page and telling the old renderer process to unload (more)Page life cycle) :

Service Worker

The Service Worker allows developers to have more control over what is cached locally and when new data is fetched from the network. If the service worker is set to load pages from the cache, there is no need to request data from the network.

Note: The Service Worker is JavaScript code that runs in the renderer process.

But how does the browser process know which site has a Service Worker when a navigation request comes in?

After a Service Worker is registered, the scope of the Service Worker is preserved. When navigation occurs, the network thread checks the domain against the scope of the registered Service Worker, and if the Service Worker has been registered for the URL, the UI thread looks for the renderer process 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.

The UI thread in the browser process starts the renderer process to handle the service worker. The worker thread in the renderer process then requests data from the network:

Navigation preloading

If the Service Worker ultimately decides to request data from the network, this round-trip between the browser process and the renderer process can cause delays. Navigation Preloads are a mechanism to speed up the process by loading resources at the same time the Service Worker starts. It marks these requests with a header, allowing the server to decide to send different content for these requests; For example, just update data rather than complete documentation.

Second, the rendering

After navigation, the browser calls the renderer (UI) process to work. The Renderer process is responsible for almost everything within a Tab, with the core job being to turn HTML, CSS, and JavaScript into web pages that users can interact with. It mainly contains the following threads:

  • Main thread
  • Worker thread Worker thread
  • Compositor threads
  • Raster thread

1. Build the DOM

The main thread parses the text string into the DOM when the renderer process receives the navigation acknowledgement and begins to accept HTML data. Methods for rendering HTML to the DOM are defined by the HTML Standard.

2. Load subresources

External resources such as images, CSS, and JS in web pages are usually obtained from the network or cache. The main process can request them one by one as it builds the DOM. To speed up the preload scanner runs at the same time. If there are tags such as in the HTML, The Preload scanner passes these requests to network Threads in the Browser process for downloading resources.

3. Download and execute JS

When a

If JavaScript doesn’t use document.write(), you can add async or defer properties to the

4. Style calculation

Rendering the DOM alone is not enough to get the exact style of the page. The main process also parses the CSS based on the CSS selector to get the final computed style value for each node. Browsers have a default style for each element, even if they don’t provide any CSS. Default style sheet

Layout of 5.

The process is to know the position of each node on the page, and the main thread traverses the DOM and calculates the style and creates a layout tree that contains information such as xy coordinates and bounding box sizes. If display: None is applied, the element is not part of the layout tree (however, having visibility: hidden is in the layout tree). Similarly, if a pseudo-class with similar content is applied, p::before{content:”Hi!” } Even if it is not in the DOM, it is included in the layout tree.

6. Draw

So far, you have the DOM, style, and layout, but to start drawing you need to decide in what order you want to draw. For example, z-index might be set for some elements, in which case drawing in the order of the elements written in HTML would result in incorrect rendering.

In the draw step, the main thread traverses the layout tree to create the draw record. The sequence of drawing records is: background first, text then rectangle. This is similar to the drawing process of

.

Note: The most important thing about the drawing process is that each step of the drawing uses the results of the previous operation to create new data. If something in the layout tree changes, you need to regenerate the drawing order for the affected portions of the document.

7. Synthesis of frame

The browser’s handling of events

1. Input events of the browser

From the browser’s point of view, all of the user’s gestures are input, mouse scrolling, hover, clicking, and so on.

When a user triggers a gesture such as touch on the screen, the Browser process first receives the gesture information, but the Browser Process only knows where the gesture occurred, and processing of the TAB content is still controlled by the rendering process.

When an event occurs, the browser process sends the event type (such as TouchStart) and its coordinates to the renderer process, which handles the event by looking for the event target and running an attached event listener.

Here’s how Input events are routed to the renderer process by the browser process:

2. Non-fast rolling area

If no input event listeners are attached to the page, the synthesizer thread can create a new composite frame that is completely independent of the main thread. If some event listeners are attached to the page, how can the synthesizer thread determine whether the event needs to be handled?

Because it is the main thread’s job to run JavaScript, when composing a page, the synthesizer thread marks the area of the page with event handlers attached as a “non-fast scrollable area.” By obtaining this information, the synthesizer thread can ensure that the input event is sent to the main thread when an event occurs in that region. If the input event comes from outside the region, the synthesizer thread continues to synthesize new frames without waiting for the main thread.

3. Event delegation

A common pattern of event handling in development is event delegation. Because the event bubbles, you can attach an event handler to the top-level element and delegate tasks based on the event target, such as:

document.body.addEventListener('touchstart', collegeevent= > {
    if(event.target === area) { event.preventDefault(); }} college);Copy the code

This event-delegate pattern is attractive if you need to write an event handler for all elements. However, if you look at the code from the browser’s point of view, the entire page is now marked as a non-fast scrollable area. This means that even if the program doesn’t care about input from some part of the page, the synthesizer thread must communicate with the main thread and wait for it every time an input event comes in. Thus, the mode in which a smooth synthesizer handles the composite frame independently fails.

To prevent this, we can pass passive: true to the event handler so that the browser listens for the event and the combinator thread builds a new composite frame before the main thread responds.

document.body.addEventListener('touchstart', collegeevent= > {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true} college);Copy the code

4. Check whether the event can be canceled

There was a scene where there was only horizontal scrolling, but no vertical scrolling.

For example, if you want to scroll horizontally in a certain area, use passive: True will allow smooth scrolling, but the vertical scrolling may occur before event.preventDefault(), which can be prevented by event.cancelable.

document.body.addEventListener('pointermove'.event= > {
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /* * do what you want the application to do here */}}, {passive: true});
Copy the code

You can also use the CSS attribute touch-action to completely eliminate the effect of the event handler, as in:

#area { 
  touch-action: pan-x; 
}
Copy the code

5. Find event objects

When a synthesizer thread sends an input event to the main thread, the first thing it runs is a hit to find the event target. Hit uses the draw record data generated during rendering to find out below the coordinates of the point where the event occurred.

6. Event optimization: Minimize event scheduling to the main thread

Given that the typical monitor refreshes the screen 60 times per second, and that we need to keep pace to get smooth animation. For input. A typical touchscreen device delivers 60-120 touch events per second, and a typical mouse delivers 100 events per second. The fidelity of input events is higher than our screens can refresh.

If a continuous event like TouchMove is sent to the main thread 120 times per second, it might trigger too many hits and JavaScript executions compared to the speed of the screen refresh:

To minimize too many calls to the main thread, Chrome merges successive events (such as wheel, MouseWheel, Mousemove, Pointermove, TouchMove) and delays scheduling until the next requestAnimationFrame, You can see that the timeline is the same, but the events are merged and delayed.

Non-continuous events such as KeyDown, KeyUp, MouseUp, mouseDown, TouchStart, and TouchEnd are executed immediately.

7. UsegetCoalescedEventsGet the in-frame event

The coalescedevents API can be used to obtain coalescedevents information, although coalescedevents can provide performance hints, if your application is drawing, it is difficult to draw a smooth curve. Example code is as follows:

window.addEventListener('pointermove'.event= > {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.}});Copy the code

The image below shows a smooth touch gesture path on the left and a combined finite path on the right:

Related links:

  • CPU, GPU, Memory, and multi-process architecture
  • What happens in navigation
  • Inner workings of a Renderer Process
  • Input is coming to the Compositor
  • How browsers work: Behind the scenes of the new Web browser
  • Is JavaScript Single-Threaded?
  • Resource Prioritization — Getting the Browser to Help You