This is the 11th chapter of how JavaScript works.
So far, the previous series of JavaScript working principles has focused on the functionality of the JavaScript language itself, how it performs in the browser, how to optimize, and so on.
However, when building Web applications, it's not just about writing your own JavaScript code that runs. The JavaScript code you write is closely related to the operating environment. Understanding the JavaScript runtime environment, how it works and how it's made up will allow you to build better applications and, once the application is running in a variety of environments, give you a more confident response to potential problems.
This article will focus on the rendering engine, as it is used to handle parsing and visualization of HTML and CSS, and these are aspects that most JavaScript applications need to continue to interact with.
The main responsibility of the rendering engine is to display the requested page on the browser screen.
The rendering engine can display Html,xml documents as well as pictures. If you use an extra plug-in, you can display different types of documents, such as PDFs.
Similar to the JavaScript engine, different browsers also use different rendering engines. The following are the more popular engines:
The rendering engine obtains the requested document content from the network layer.
The first step in the rendering engine is to parse the HTML document and convert the parsed elements into the actual DOM nodes on the DOM tree.
Building the CSSOM TreeCSSOM is the CSS Object Model. When the browser builds the page's DOM tree, it head
encounters a link tag that references an external style sheet in the label section theme.css
. Indicates that it may require a stylesheet to render the page, so a request is dispatched immediately to get the style sheet. Suppose the following is the theme.css
file content:
body { font-size: 16px;}p { font-weight: bold; }span { color: red; }p span { display: none; }img { float: right; }
Like HTML, the rendering engine needs to turn CSS into something that the browser can manipulate-that is, CSSOM. The following is the approximate appearance of CSSOM:
Want to know why CSSOM is a tree-like structure? When the final set of styles is computed for any object on the page, the browser first applies the most common style rule to the node (for example, it is a child of the body, applies all of the body's styles first) and then recursively redefine the calculated style by applying more specific style rules.
Let's take a look at specific examples. body
span
any text style in the label is 16 pixels in font size and the font color is red. These styles inherit from the body
element. p
the element's child element span
does not display its contents () because it applies a more specific style display:none
.
Also, note that the CSSOM tree above is not complete and only shows the overridden style specified in the style sheet. Each browser provides a default set of styles-the user-agent style-which is the default display style when no style is provided. Our style simply overrides these default styles.
Build a render TreeThe visual directives in HTML are combined with the style data of the CSSOM tree to create a render tree.
You may be asking what is the rendering tree? It is a tree that builds visual elements sequentially and displays them on the screen. It is the visual representation of HTML with the corresponding style. The tree is designed to draw content in the correct order.
Each node in the render tree in Webkit is a renderer or renderer object.
The following is the approximate appearance of the renderer tree for the above DOM and CSSOM tree composition:
In order to create a render tree, the browser probably did a few things:
- Iterates through each visible node, starting at the root node of the DOM tree. Some nodes are invisible (such as script tags, meta tags, and so on), and are then ignored because they are not displayed in the rendered output. Some nodes are hidden by style and are also ignored. For example, the span node in the example above, because the style is explicitly set for it
display: none
.
- The browser applies the corresponding CSSOM rules for each visible node and applies the style rules.
- Releases the visible nodes that contain the contents and their computed styles.
Can browse the source of the next RenderObject (in Webkit): https://github.com/WebKit/webkit/blob/fde57e46b1f8d7dde4b2006aaf7ebe5a09a6984b/ Source/webcore/rendering/renderobject.h
Take a look at some of the core components of this class:
class RenderObject : public CachedImageClient { // 重绘整个对象。当边框颜色改变或者边框样式更改的时候调用。 Node* node() const { ... } RenderStyle* style; // 计算的样式 const RenderStyle& style() const; ...}
Each renderer object represents a rectangular area that is typically relative to a node's CSS box model. It includes geometric information such as width, height, and positioning.
Render Tree LayoutWhen a renderer is created and added to the render tree, it has no information about the location and size. Calculating these values is called layout.
HTML uses a streaming layout model, meaning that in most cases the geometry information of the renderer can be computed at once. The coordinate system is relative to the root renderer. The Top and left coordinates are used here.
A layout is a recursive process-it starts rendering from the root renderer, which is the element of the HTML document html
. The layout continues recursively through some or all of the renderer hierarchies, calculating its information for each renderer that needs to calculate the geometry information.
The root renderer is positioned 0,0
and sized as a visual part of the browser window (such as viewport).
The process of laying out calculates exactly where each node appears on the screen.
Draw a render treeAt this stage, the renderer tree is traversed and the renderer's method is called paint()
to display its contents on the screen.
Drawing can be global or incremental (similar to layout):
- Global-redraws the entire tree.
- Increment-changes only part of the renderer in some way without affecting the entire tree. The renderer invalidates its rectangular area on the screen. This causes the operating system to think of it as a region that needs to be redrawn and generates an
paint
event. The operating system intelligently merges several areas into one to improve rendering performance.
In conclusion, it is important to understand that drawing is a gradual process. For a better interactive experience, the rendering engine tries to display content on the screen as soon as possible. It does not wait for all HTML structure parsing to complete before starting to build and layout the render tree. Will prioritize parsing and displaying portions of content, while continuing to process the remaining content items received from the network.
Processing order of scripts and stylesThe <script>
code inside the tag is parsed and executed immediately when the parser encounters the tag. Parsing of the entire document stops until the script finishes executing. Meaning that the process is synchronous.
When a script refers to an external resource, it must first get the resource (also synchronized). All parsing stops until the script resource is fetched.
HTML5 adds an option to load the resource asynchronously so that another thread can be used to parse and execute the resource. IE can use defer
attributes, others can use the async attribute. IE10 use the Defer property below, IE10 can also use the Async property.
Here's one thing to be aware of is that IE10 the following for defer support, open https://caniuse.com find to find support for IE10 below is a few things to note that the defer script may be in the Domcontentloaded event Before starting to run, see here, do not experiment here, interested can click here to test the performance under IE.
Here to do a little extension, in the JQuery source code, Ready.js has a section of the following codes:
// Catch cases where $(document).ready() is called// after the browser event has already occurred.// Support: IE <=9 - 10 only// Older IE sometimes signals "interactive" too soonif ( document.readyState === "complete" ||( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {// Handle it asynchronously to allow scripts the opportunity to delay readywindow.setTimeout( jQuery.ready );} else {// Use the handy event callbackdocument.addEventListener( "DOMContentLoaded", completed );// A fallback to window.onload, that will always workwindow.addEventListener( "load", completed );}
Inside window.setTimeout( jQuery.ready );
is a chance to allow the script to defer execution of the Ready event. It's probably for the defer property of the IE script tag, right?
Optimize rendering PerformanceTo optimize the performance of your network applications, you need to focus on five main areas. These are things you can control:
- Previous articles in javascript-have described writing non-blocking UI, efficient code, and so on. When it comes to rendering, consider how the JavaScript code interacts with the DOM elements on the page. JavaScript makes a lot of changes to the interface, especially in a single page application.
- Style calculation-This process applies the style rule to the element that matches the selector. Once a style rule is defined, they are applied to the corresponding element, and then the final style of each element is calculated.
- Layout-Once the browser understands the style rules applied by the element, it begins to calculate the space occupied by the element and where it appears on the browser screen. Defining the layout of one element according to the layout model of a Web page affects other elements. For example,
<body>
the width of a label affects the width of its descendants, and so on. This means that the layout process is quite time-consuming. Drawing is done on multiple layers.
- Draw-This stage begins to populate the actual pixel. This process includes drawing text, colors, pictures, borders, shadows, and all the visible parts of each element.
- Compositing-because the page sections are drawn as potential multilayer, they must be drawn in the correct order on the screen so that the page render is normal. This is crucial, especially for those overlapping elements.
Optimizing JavaScript CodeJavaScript often triggers visual changes on the browser side. Especially in the process of building a SPA.
Here are some suggestions for optimizing some of the code in JavaScript to improve rendering efficiency:
Avoid using setTimeout
or setInterval
to make visual changes. These are called at some point in the frame callback
, possibly at the end of the frame. This will cause the Dayton. Visual changes must be triggered at the beginning of the frame.
Move the time-consuming JavaScript into the previously mentioned web worker thread.
Use a micro task to handle DOM changes across multiple frames. This is to prevent situations where a task needs to access the DOM while the network worker thread is unable to do so.
This means that a large task needs to be divided into smaller tasks and then executed according to the nature of the tasks requestAnimationFrame
setTimeout
setInterval
.
Refine styleModifying the DOM by adding and removing elements and changing properties can cause the browser to recalculate the element style and the layout of the entire page or part of the page in most cases.
Use the following methods to optimize rendering:
- Reduce the complexity of selectors. The selector complexity takes up 50% of the time required to calculate the desired element style, and the remaining time is the build style itself.
- Reduce the number of elements that must produce a style calculation. Essentially, the style of a few elements is changed directly instead of invalidating the style of the entire page.
Optimizing layoutsLayout is a very expensive browser performance. Consider the following optimization scenarios:
- Reduce the number of layouts as much as possible. When you change the style, the browser checks whether the style changes require a recalculation of the layout. Generally changing attributes such as width, height, left, top, and geometry will require layout. Therefore, avoid modifying them as much as possible.
- Use it as much as possible for
flexbox
layout rather than old-fashioned layout models. It renders faster and can dramatically improve the performance of your network applications.
- Avoid forcing a synchronized layout. Remember that when you run JavaScript, the old layout values of the previous frame are known and can be queried.
box.offsetHeight
This does not cause performance problems when accessed. However, if you change its style before accessing it (such as adding a style class to an element dynamically), the browser will have to apply the style changes first and then run the layout calculation style. This will be time consuming and resource intensive, so try to avoid doing so.
Optimized drawingThis is often the most time-consuming of all tasks, so try to avoid triggering the drawing. Optimization scenarios:
- Changing a property other than transfroms or opacity will trigger drawing. So save it for a little bit.
- Drawing is also triggered when a layout is triggered, because changing the geometry information of an element changes the appearance of the element.
- Reduce the area of paint by lifting layers and animation choreography.
ExtendedRefer to Google's official documentation on performance, the following code is used for lifting elements:
.moving-element { will-change: transform;}
Use Fastdom to avoid forcing synchronous layout and jitter.
In addition to the optimization of JavaScript code, to avoid the processing of some micro-optimization, such as the use offsetTop
getBoundingClientRect
of faster than the speed, but this is based on the network application created, suppose to create a game, the performance requirements are very high and call these methods more places, Then the performance improvement will be considerable. Remember that you used to use such as jsperf to test a method of speed, do not be in the dead, local conditions, to avoid falling into the small optimization and pay too much energy.
About rendering you can use some skeleton diagrams to improve the user experience.
Some ideas
- As for the performance experience, you can actually imagine building a house, which would be more time-consuming if it was the entire refurbishment, but would improve performance if a certain area was renovated.
- Then there is one of those properties that improves performance, which may be understood as "工欲善其事 its prerequisite".
- The segmentation of the task can be understood as the philosophy of building design, tips.
Reference Resources
- Https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model
- Https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations
- https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/#The_parsing_algorithm
How JavaScript works (JavaScript works) (11) Rendering engine and performance tuning tips