性能
2020-04-16 11:08:33 0 举报
AI智能生成
前端性能知识总结
作者其他创作
大纲/内容
性能基础
性能是什么
Ultimately, user-perceived performance is the only performance that matters.
Performance is the quality of system outputs in response to user inputs.
Performance is the quality of system outputs in response to user inputs.
核心性能指标
Responsiveness
Responsiveness simply means how fast the system provides outputs (possibly multiple ones) in response to user inputs.
Frame-rate
Framerate is the rate at which the system changes pixels displayed to the user.
Humans usually cannot perceive differences in frame-rate above 60Hz.
That's why most modern electronic displays are designed to refresh at that rate.
That's why most modern electronic displays are designed to refresh at that rate.
Memory usage
All applications would retain the state created by the user the last time the user interacted with the application.
A well-designed system has been optimized to use as much memory as possible to maintain user state, while meeting other UPP goals.
A well-designed system has been optimized to use as much memory as possible to maintain user state, while meeting other UPP goals.
Power usage
In service of meeting UPP goals, the system must use only the minimum power required.
how Firefox/Gecko contributes to performance
"What does the platform do for you?"
"What does the platform do for you?"
Web technologies
The Web platform provides many tools, some better suited for particular jobs than others.
All application logic is written in JavaScript.
To display graphics, developers can use HTML or CSS (i.e. high-level declarative languages), or use low-level imperative interfaces offered by the <canvas> element (which includes WebGL).
Somewhere "in between" HTML/CSS and Canvas is SVG, which offers some benefits of both.
HTML and CSS greatly increase productivity, sometimes at the expense of framerate or pixel-level control over rendering.
Text and images reflow automatically, UI elements automatically receive the system theme, and the system provides "built-in" support for some use cases developers may not think of initially, like different-resolution displays or right-to-left languages.
The canvas element offers a pixel buffer directly for developers to draw on. This gives developers pixel-level control over rendering and precise control of framerate, but now the developers need to deal with multiple resolutions and orientations, right-to-left languages, and so forth.
Developers draw to canvases using either a familiar 2D drawing API, or WebGL
All application logic is written in JavaScript.
To display graphics, developers can use HTML or CSS (i.e. high-level declarative languages), or use low-level imperative interfaces offered by the <canvas> element (which includes WebGL).
Somewhere "in between" HTML/CSS and Canvas is SVG, which offers some benefits of both.
HTML and CSS greatly increase productivity, sometimes at the expense of framerate or pixel-level control over rendering.
Text and images reflow automatically, UI elements automatically receive the system theme, and the system provides "built-in" support for some use cases developers may not think of initially, like different-resolution displays or right-to-left languages.
The canvas element offers a pixel buffer directly for developers to draw on. This gives developers pixel-level control over rendering and precise control of framerate, but now the developers need to deal with multiple resolutions and orientations, right-to-left languages, and so forth.
Developers draw to canvases using either a familiar 2D drawing API, or WebGL
Gecko rendering
The Gecko JavaScript engine supports just-in-time (JIT) compilation.
This enables application logic to perform comparably to other virtual machines — such as Java virtual machines — and in some cases even close to "native code".
The graphics pipeline in Gecko that underpins HTML, CSS, and Canvas is optimized in several ways. The HTML/CSS layout and graphics code in Gecko reduces invalidation and repainting for common cases like scrolling; developers get this support "for free". Pixel buffers painted by both Gecko "automatically" and applications to canvas "manually" minimize copies when being drawn to the display framebuffer. This is done by avoiding intermediate surfaces where they would create overhead (such as per-application "back buffers" in many other operating systems), and by using special memory for graphics buffers that can be directly accessed by the compositor hardware.
Complex scenes are rendered using the device's GPU for maximum performance.
To improve power usage, simple scenes are rendered using special dedicated composition hardware, while the GPU idles or turns off.
Fully static content is the exception rather than the rule for rich applications. Rich applications use dynamic content with animation and transition effects. Transitions and animations are particularly important to applications: developers can use CSS to declare complicated behaviour with a simple, high-level syntax. In turn, Gecko's graphics pipeline is highly optimized to render common animations efficiently.
Common-case animations are "offloaded" to the system compositor, which can render them in a performant, power-efficient fashion.
An app's startup performance matters just as much as its runtime performance. Gecko is optimized to load a wide variety of content efficiently: the entire Web! Many years of improvements targeting this content, like parallel HTML parsing, intelligent scheduling of reflows and image decoding, clever layout algorithms, etc., translate just as well to improving Web applications on Firefox.
This enables application logic to perform comparably to other virtual machines — such as Java virtual machines — and in some cases even close to "native code".
The graphics pipeline in Gecko that underpins HTML, CSS, and Canvas is optimized in several ways. The HTML/CSS layout and graphics code in Gecko reduces invalidation and repainting for common cases like scrolling; developers get this support "for free". Pixel buffers painted by both Gecko "automatically" and applications to canvas "manually" minimize copies when being drawn to the display framebuffer. This is done by avoiding intermediate surfaces where they would create overhead (such as per-application "back buffers" in many other operating systems), and by using special memory for graphics buffers that can be directly accessed by the compositor hardware.
Complex scenes are rendered using the device's GPU for maximum performance.
To improve power usage, simple scenes are rendered using special dedicated composition hardware, while the GPU idles or turns off.
Fully static content is the exception rather than the rule for rich applications. Rich applications use dynamic content with animation and transition effects. Transitions and animations are particularly important to applications: developers can use CSS to declare complicated behaviour with a simple, high-level syntax. In turn, Gecko's graphics pipeline is highly optimized to render common animations efficiently.
Common-case animations are "offloaded" to the system compositor, which can render them in a performant, power-efficient fashion.
An app's startup performance matters just as much as its runtime performance. Gecko is optimized to load a wide variety of content efficiently: the entire Web! Many years of improvements targeting this content, like parallel HTML parsing, intelligent scheduling of reflows and image decoding, clever layout algorithms, etc., translate just as well to improving Web applications on Firefox.
应用性能
Startup performance
三个用户可见事件
The first is the application first paint — the point at which sufficient application resources have been loaded to paint an initial frame
The second is when the application becomes interactive — for example, users are able to tap a button and the application responds
The final event is full load — for example when all the user's albums have been listed in a music player
The second is when the application becomes interactive — for example, users are able to tap a button and the application responds
The final event is full load — for example when all the user's albums have been listed in a music player
key to fast startup
keep two things in mind:
UPP is all that matters,
and there's a "critical path" to each user-perceived event above.
to reach a user-perceived startup event more quickly,
the main "trick" is run only the code on the critical path.
Shorten the critical path by simplifying the scene.
UPP is all that matters,
and there's a "critical path" to each user-perceived event above.
to reach a user-perceived startup event more quickly,
the main "trick" is run only the code on the critical path.
Shorten the critical path by simplifying the scene.
减少请求等待时间
预请求
合理设置缓存
帧率
The first important thing for high framerate is to choose the right tool.
Use HTML and CSS to implement content that's mostly static, scrolled, and infrequently animated.
Use Canvas to implement highly dynamic content, like games that need tight control over rendering and don't need theming.
For content drawn using Canvas, it's up to the developer to hit framerate targets: they have direct control over what's drawn.
For HTML and CSS content, the path to high framerate is to use the right primitives. Firefox is highly optimized to scroll arbitrary content; this is usually not a concern. But often trading some generality and quality for speed, such as using a static rendering instead of a CSS radial gradient, can push scrolling framerate over a target. CSS media queries allow these compromises to be restricted only to devices that need them.
Many applications use transitions or animations through "pages", or "panels". For example, the user taps a "Settings" button to transition into an application configuration screen, or a settings menu "pops up".
Firefox is highly optimized to transition and animate scenes that:
Use HTML and CSS to implement content that's mostly static, scrolled, and infrequently animated.
Use Canvas to implement highly dynamic content, like games that need tight control over rendering and don't need theming.
For content drawn using Canvas, it's up to the developer to hit framerate targets: they have direct control over what's drawn.
For HTML and CSS content, the path to high framerate is to use the right primitives. Firefox is highly optimized to scroll arbitrary content; this is usually not a concern. But often trading some generality and quality for speed, such as using a static rendering instead of a CSS radial gradient, can push scrolling framerate over a target. CSS media queries allow these compromises to be restricted only to devices that need them.
Many applications use transitions or animations through "pages", or "panels". For example, the user taps a "Settings" button to transition into an application configuration screen, or a settings menu "pops up".
Firefox is highly optimized to transition and animate scenes that:
- use pages/panels approximately the size of the device screen or smaller
- transition/animate the CSS transform and opacity properties
Memory and power usage
Improving memory and power usage is a similar problem to speeding up startup:
don't do unneeded work or lazily load uncommonly-used UI resources.
Do use efficient data structures and ensure resources like images are optimized well.
Modern CPUs can enter a lower-power mode when mostly idle.
Applications that constantly fire timers or keep unnecessary animations running prevent CPUs from entering low-power mode. Power-efficient applications shouldn't do that.
When applications are sent to the background, a visibilitychange event is fired on their documents.
This event is a developer's friend; applications should listen for it.
don't do unneeded work or lazily load uncommonly-used UI resources.
Do use efficient data structures and ensure resources like images are optimized well.
Modern CPUs can enter a lower-power mode when mostly idle.
Applications that constantly fire timers or keep unnecessary animations running prevent CPUs from entering low-power mode. Power-efficient applications shouldn't do that.
When applications are sent to the background, a visibilitychange event is fired on their documents.
This event is a developer's friend; applications should listen for it.
具体编码建议
Use CSS animations and transitions
Instead of using some library’s animate() function, which probably currently uses many badly performing technologies (window.setTimeout() or top/left positioning, for example) use CSS animations. In many cases, you can actually use CSS Transitions to get the job done.
This works well because the browser is designed to optimize these effects and use the GPU to handle them smoothly with minimal impact on processor performance. Another benefit is that you can define these effects in CSS along with the rest of your app's look-and-feel, using a standardized syntax.
CSS animations give you very granular control over your effects using keyframes, and you can even watch events fired during the animation process in order to handle other tasks that need to be performed at set points in the animation process. You can easily trigger these animations with the :hover, :focus, or :target, or by dynamically adding and removing classes on parent elements.
If you want to create animations on the fly or modify them in JavaScript, James Long has written a simple library for that called CSS-animations.js.
This works well because the browser is designed to optimize these effects and use the GPU to handle them smoothly with minimal impact on processor performance. Another benefit is that you can define these effects in CSS along with the rest of your app's look-and-feel, using a standardized syntax.
CSS animations give you very granular control over your effects using keyframes, and you can even watch events fired during the animation process in order to handle other tasks that need to be performed at set points in the animation process. You can easily trigger these animations with the :hover, :focus, or :target, or by dynamically adding and removing classes on parent elements.
If you want to create animations on the fly or modify them in JavaScript, James Long has written a simple library for that called CSS-animations.js.
Use CSS transforms
Instead of tweaking absolute positioning and fiddling with all that math yourself, use the transform CSS property to adjust the position, scale, and so forth of your content. The reason is, once again, hardware acceleration. The browser can do these tasks on your GPU, letting the CPU handle other things.
In addition, transforms give you capabilities you might not otherwise have.
Not only can you translate elements in 2D space, but you can transform in three dimensions, skew and rotate, and so forth.
Paul Irish has an in-depth analysis of the benefits of translate() from a performance point of view. In general, however, you have the same benefits you get from using CSS animations: you use the right tool for the job and leave the optimization to the browser. You also use an easily extensible way of positioning elements — something that needs a lot of extra code if you simulate translation with top and left positioning. Another bonus is that this is just like working in a canvas element.
In addition, transforms give you capabilities you might not otherwise have.
Not only can you translate elements in 2D space, but you can transform in three dimensions, skew and rotate, and so forth.
Paul Irish has an in-depth analysis of the benefits of translate() from a performance point of view. In general, however, you have the same benefits you get from using CSS animations: you use the right tool for the job and leave the optimization to the browser. You also use an easily extensible way of positioning elements — something that needs a lot of extra code if you simulate translation with top and left positioning. Another bonus is that this is just like working in a canvas element.
You may need to attach a translateZ(0.1) transform if you wish to get hardware acceleration on your CSS animations, depending on platform. As noted above, this can improve performance, but can also have memory consumption issues. What you do in this regard is up to you — do some testing and find out what's best for your particular app.
Use requestAnimationFrame()
instead of setInterval()
instead of setInterval()
Calls to window.setInterval() run code at a presumed frame rate that may or may not be possible under current circumstances. It tells the browser to render results even while the browser isn't actually drawing; that is, while the video hardware hasn't reached the next display cycle. This wastes processor time and can even lead to reduced battery life on the user's device.
Instead, you should try to use window.requestAnimationFrame().
This waits until the browser is actually ready to start building the next frame of your animation, and won't bother if the hardware isn't going to actually draw anything.
Another benefit to this API is that animations won't run while your app isn't visible on the screen (such as if it's in the background and some other task is operating). This will save battery life and prevent users from cursing your name into the night sky.
Instead, you should try to use window.requestAnimationFrame().
This waits until the browser is actually ready to start building the next frame of your animation, and won't bother if the hardware isn't going to actually draw anything.
Another benefit to this API is that animations won't run while your app isn't visible on the screen (such as if it's in the background and some other task is operating). This will save battery life and prevent users from cursing your name into the night sky.
Make events immediate
As old-school, accessibility-aware Web developers we love click events since they also support keyboard input.
On mobile devices, these are too slow. You should use touchstart and touchend instead.
The reason is that these don’t have a delay that makes the interaction with the app appear sluggish.
If you test for touch support first, you don’t sacrifice accessibility, either.
For example, the Financial Times uses a library called fastclick for that purpose, which is available for you to use.
(fast-click 是 test for touch support first ??根据其文档,目前手机都已经没有 300ms 延迟了,那也就不用考虑引入 fast-click 了)
As of late 2015 most mobile browsers - notably Chrome and Safari - no longer have a 300ms touch delay, so fastclick offers no benefit on newer browsers, and risks introducing bugs into your application. Consider carefully whether you really need to use it.
On mobile devices, these are too slow. You should use touchstart and touchend instead.
The reason is that these don’t have a delay that makes the interaction with the app appear sluggish.
If you test for touch support first, you don’t sacrifice accessibility, either.
For example, the Financial Times uses a library called fastclick for that purpose, which is available for you to use.
(fast-click 是 test for touch support first ??根据其文档,目前手机都已经没有 300ms 延迟了,那也就不用考虑引入 fast-click 了)
As of late 2015 most mobile browsers - notably Chrome and Safari - no longer have a 300ms touch delay, so fastclick offers no benefit on newer browsers, and risks introducing bugs into your application. Consider carefully whether you really need to use it.
Keep your interface simple
One big performance issue we found in HTML5 apps was that moving lots of DOM elements around makes everything sluggish — especially when they feature lots of gradients and drop shadows. It helps a lot to simplify your look-and-feel and move a proxy element around when you drag and drop.
When, for example, you have a long list of elements (let’s say tweets), don’t move them all.
Instead, keep in your DOM tree only the ones that are visible and a few on either side of the currently visible set of tweets.
Hide or remove the rest.
Keeping the data in a JavaScript object instead of accessing the DOM can vastly improve your app's performance.
Think of the display as a presentation of your data rather than the data itself.
That doesn’t mean you can't use straight HTML as the source; just read it once and then scroll 10 elements,
changing the content of the first and last accordingly to your position in the results list, instead of moving 100 elements that aren’t visible.
The same trick applies in games to sprites: if they aren’t currently on the screen, there is no need to poll them.
Instead re-use elements that scroll off screen as new ones coming in.
When, for example, you have a long list of elements (let’s say tweets), don’t move them all.
Instead, keep in your DOM tree only the ones that are visible and a few on either side of the currently visible set of tweets.
Hide or remove the rest.
Keeping the data in a JavaScript object instead of accessing the DOM can vastly improve your app's performance.
Think of the display as a presentation of your data rather than the data itself.
That doesn’t mean you can't use straight HTML as the source; just read it once and then scroll 10 elements,
changing the content of the first and last accordingly to your position in the results list, instead of moving 100 elements that aren’t visible.
The same trick applies in games to sprites: if they aren’t currently on the screen, there is no need to poll them.
Instead re-use elements that scroll off screen as new ones coming in.
浏览器如何工作
概述
性能面临
的两个问题
的两个问题
延迟
Latency is our main threat to overcome to ensure a fast load.
To be fast to load, the developers’ goals include sending requested information as fast as possible,
or at least seem super fast.
Network latency is the time it takes to transmit bytes over-the-air to computers.
Web performance is what we have to do to make the page load happen as quickly as possible.
To be fast to load, the developers’ goals include sending requested information as fast as possible,
or at least seem super fast.
Network latency is the time it takes to transmit bytes over-the-air to computers.
Web performance is what we have to do to make the page load happen as quickly as possible.
浏览器的单线程
minimizing the main thread's responsibilities, where possible and appropriate,
to ensure rendering is smooth and responses to interactions are immediate.
to ensure rendering is smooth and responses to interactions are immediate.
1. 与Web 服务器
建立连接
(这个流程里没有讲关闭连接)
建立连接
(这个流程里没有讲关闭连接)
1.1 DNS Lookup
The first step of navigating to a web page is finding where the assets for that page are located.
If you navigate to https://example.com, the HTML page is located on the server with IP address of 93.184.216.34.
If you’ve never visited this site, a DNS lookup must happen.
Your browser requests a DNS lookup, which is eventually fielded by a name server, which in turn responds with an IP address.
After this initial request, the IP will likely be cached for a time, which speeds up subsequent requests by retrieving the IP address from the cache instead of contacting a name server again.
DNS lookups usually only need to be done once per hostname for a page load.
However, DNS lookups must be done for each unique hostname the requested page references.
If your fonts, images, scripts, ads, and metrics all have different hostnames, a DNS lookup will have to be made for each one.
This can be problematic for performance, particularly on mobile networks.
When a user is on a mobile network, each DNS lookup has to go from the phone to the cell tower to reach an authoritative DNS server.
The distance between a phone, a cell tower, and the name server can add significant latency.
If you navigate to https://example.com, the HTML page is located on the server with IP address of 93.184.216.34.
If you’ve never visited this site, a DNS lookup must happen.
Your browser requests a DNS lookup, which is eventually fielded by a name server, which in turn responds with an IP address.
After this initial request, the IP will likely be cached for a time, which speeds up subsequent requests by retrieving the IP address from the cache instead of contacting a name server again.
DNS lookups usually only need to be done once per hostname for a page load.
However, DNS lookups must be done for each unique hostname the requested page references.
If your fonts, images, scripts, ads, and metrics all have different hostnames, a DNS lookup will have to be made for each one.
This can be problematic for performance, particularly on mobile networks.
When a user is on a mobile network, each DNS lookup has to go from the phone to the cell tower to reach an authoritative DNS server.
The distance between a phone, a cell tower, and the name server can add significant latency.
1.2 TCP Handshake
Once the IP address is known, the browser sets up a connection to the server via a TCP three-way handshake.
This mechanism is designed so that two entities attempting to communicate—in this case the browser and web server
—can negotiate the parameters of the network TCP socket connection before transmitting data, often over HTTPS.
TCP's three way handshaking technique is often referred to as
"SYN-SYN-ACK"—or more accurately SYN, SYN-ACK, ACK
—because there are three messages transmitted by TCP to negotiate and start a TCP session between two computers.
Yes, this means three more messages back and forth between each server, and the request has yet to be made.
This mechanism is designed so that two entities attempting to communicate—in this case the browser and web server
—can negotiate the parameters of the network TCP socket connection before transmitting data, often over HTTPS.
TCP's three way handshaking technique is often referred to as
"SYN-SYN-ACK"—or more accurately SYN, SYN-ACK, ACK
—because there are three messages transmitted by TCP to negotiate and start a TCP session between two computers.
Yes, this means three more messages back and forth between each server, and the request has yet to be made.
三次握手
SYN
SYNchronize
The host, generally the browser, sends a TCP SYNchronize packet to the server.
SYN-ACK
SYNchronize-ACKnowledgement
The server receives the SYN and sends back a SYNchronize-ACKnowledgement.
ACK
ACKnowledge
The host receives the server's SYN-ACK and sends an ACKnowledge.
The server receives ACK and the TCP socket connection is established.
The server receives ACK and the TCP socket connection is established.
1.3 TLS Negotiation
For secure connections established over HTTPS, another "handshake" is required.
This handshake, or rather the TLS negotiation,
determines which cipher will be used to encrypt the communication, verifies the server,
and establishes that a secure connection is in place before beginning the actual transfer of data.
This requires three more round trips to the server before the request for content is actually sent.
While making the connection secure adds time to the page load,
a secure connection is worth the latency expense,
as the data transmitted between the browser and the web server cannot be decrypted by a third party.
This handshake, or rather the TLS negotiation,
determines which cipher will be used to encrypt the communication, verifies the server,
and establishes that a secure connection is in place before beginning the actual transfer of data.
This requires three more round trips to the server before the request for content is actually sent.
While making the connection secure adds time to the page load,
a secure connection is worth the latency expense,
as the data transmitted between the browser and the web server cannot be decrypted by a third party.
图示总结
After the 8 round trips, the browser is finally able to make the request.
2. 请求与响应
Once we have an established connection to a web server,
the browser sends an initial HTTP GET request on behalf of the user,
which for websites is most often an HTML file.
Once the server receives the request, it will reply with
relevant response headers and the contents of the HTML.
the browser sends an initial HTTP GET request on behalf of the user,
which for websites is most often an HTML file.
Once the server receives the request, it will reply with
relevant response headers and the contents of the HTML.
TCP Slow Start / 14kb rule
The first response packet will be 14Kb.
This is part of TCP slow start, an algorithm which balances the speed of a network connection.
Slow start gradually increases the amount of data transmitted
until the network's maximum bandwidth can be determined.
In TCP slow start, after receipt of the initial packet, the server doubles the size of the next packet to around 28Kb.
Subsequent packets increase in size until a predetermined threshold is reached, or congestion is experienced.
This is part of TCP slow start, an algorithm which balances the speed of a network connection.
Slow start gradually increases the amount of data transmitted
until the network's maximum bandwidth can be determined.
In TCP slow start, after receipt of the initial packet, the server doubles the size of the next packet to around 28Kb.
Subsequent packets increase in size until a predetermined threshold is reached, or congestion is experienced.
If you’ve ever heard of the 14Kb rule for initial page load, TCP slow start is the reason why the initial response is 14Kb,
and why web performance optimization calls for focusing optimizations with this initial 14Kb response in mind.
TCP slow start gradually builds up transmission speeds appropriate for the network's capabilities to avoid congestion.
and why web performance optimization calls for focusing optimizations with this initial 14Kb response in mind.
TCP slow start gradually builds up transmission speeds appropriate for the network's capabilities to avoid congestion.
Congestion control
As the server sends data in TCP packets, the user's client confirms delivery by returning acknowledgements, or ACKs.
The connection has a limited capacity depending on hardware and network conditions.
If the server sends too many packets too quickly, they will be dropped. Meaning, there will be no acknowledgement.
The server registers this as missing ACKs.
Congestion control algorithms use this flow of sent packets and ACKs to determine a send rate.
The connection has a limited capacity depending on hardware and network conditions.
If the server sends too many packets too quickly, they will be dropped. Meaning, there will be no acknowledgement.
The server registers this as missing ACKs.
Congestion control algorithms use this flow of sent packets and ACKs to determine a send rate.
3. 解析
Parsing is the step the browser takes to turn the data it receives over the network into the DOM and CSSOM,
which is used by the renderer to paint a page to the screen.
Even if the request page's HTML is larger than the initial 14KB packet, the browser will begin parsing and attempting to render an experience based on the data it has.
This is why it's important for web performance optimization to include everything the browser needs to start rendering a page, or at least a template of the page - the CSS and HTML needed for the first render -- in the first 14 kilobytes.
But before anything is rendered to the screen, the HTML, CSS, and JavaScript have to be parsed.
which is used by the renderer to paint a page to the screen.
Even if the request page's HTML is larger than the initial 14KB packet, the browser will begin parsing and attempting to render an experience based on the data it has.
This is why it's important for web performance optimization to include everything the browser needs to start rendering a page, or at least a template of the page - the CSS and HTML needed for the first render -- in the first 14 kilobytes.
But before anything is rendered to the screen, the HTML, CSS, and JavaScript have to be parsed.
HTML 解释器将 HTML 文档
解析为 DOM 树
解析为 DOM 树
processing the HTML markup and building the DOM tree
不会导致暂停HTML解析的资源
an image
a CSS file
a CSS file
导致暂停HTML解析的资源
非异步的 <script> 标签
之所以对 <script> 标签应用阻塞式的解析策略,是因为 JS 拥有改变 HTML 文档结构的权限
Though the browser's preload scanner hastens this process,
excessive scripts can still be a significant bottleneck.
Though the browser's preload scanner hastens this process,
excessive scripts can still be a significant bottleneck.
Preload scanner
While the browser builds the DOM tree, this process occupies the main thread.
As this happens, the preload scanner will parse through the content available
and request high priority resources like CSS, JavaScript, and web fonts.
Thanks to the preload scanner, we don't have to wait until
the parser finds a reference to an external resource to request it.
It will retrieve resources in the background so that by the time
the main HTML parser reaches requested assets,
they may possibly already be in flight, or have been downloaded.
The optimizations the preload scanner provides reduce blockages.
As this happens, the preload scanner will parse through the content available
and request high priority resources like CSS, JavaScript, and web fonts.
Thanks to the preload scanner, we don't have to wait until
the parser finds a reference to an external resource to request it.
It will retrieve resources in the background so that by the time
the main HTML parser reaches requested assets,
they may possibly already be in flight, or have been downloaded.
The optimizations the preload scanner provides reduce blockages.
To ensure the script doesn't block the process,
add the async attribute, or the defer attribute
if JavaScript parsing and execution order is not important.
add the async attribute, or the defer attribute
if JavaScript parsing and execution order is not important.
Waiting to obtain CSS doesn't block HTML parsing or downloading,
but it does block JavaScript,
because JavaScript is often used to query CSS properties’ impact on elements.
but it does block JavaScript,
because JavaScript is often used to query CSS properties’ impact on elements.
CSS 解释器将 CSS
解析为 CSSOM
解析为 CSSOM
the total time to create the CSSOM is generally less than the time it takes for one DNS lookup.
Other Processes
JavaScript Compilation
While the CSS is being parsed and the CSSOM created, other assets,
including JavaScript files, are downloading (thanks to the preload scanner).
JavaScript is interpreted, compiled, parsed and executed.
The scripts are parsed into abstract syntax trees.
Some browser engines take the Abstract Syntax Tree and pass it into an interpreter,
outputting bytecode which is executed on the main thread.
This is known as JavaScript compilation.
including JavaScript files, are downloading (thanks to the preload scanner).
JavaScript is interpreted, compiled, parsed and executed.
The scripts are parsed into abstract syntax trees.
Some browser engines take the Abstract Syntax Tree and pass it into an interpreter,
outputting bytecode which is executed on the main thread.
This is known as JavaScript compilation.
Building the Accessibility Tree
The browser also builds an accessibility tree that assistive devices use to parse and interpret content.
The accessibility object model (AOM) is like a semantic version of the DOM.
The browser updates the accessibility tree when the DOM is updated.
The accessibility tree is not modifiable by assistive technologies themselves.
Until the AOM is built, the content is not accessible to screen readers.
The accessibility object model (AOM) is like a semantic version of the DOM.
The browser updates the accessibility tree when the DOM is updated.
The accessibility tree is not modifiable by assistive technologies themselves.
Until the AOM is built, the content is not accessible to screen readers.
4. 渲染
Rendering steps include style, layout, paint and, in some cases, compositing.
The CSSOM and DOM trees created in the parsing step are combined into a render tree
which is then used to compute the layout of every visible element,
which is then painted to the screen.
In some cases, content can be promoted to their own layers and composited,
improving performance by painting portions of the screen on the GPU instead of the CPU,
freeing up the main thread.
The CSSOM and DOM trees created in the parsing step are combined into a render tree
which is then used to compute the layout of every visible element,
which is then painted to the screen.
In some cases, content can be promoted to their own layers and composited,
improving performance by painting portions of the screen on the GPU instead of the CPU,
freeing up the main thread.
combining the DOM and CSSOM
into a render tree
into a render tree
The third step in the critical rendering path is combining the DOM and CSSOM into a render tree.
The computed style tree, or render tree, construction starts with the root of the DOM tree,
traversing each visible node.
Tags that aren't going to be displayed, like the <head> and its children and
any nodes with display: none, such as the script { display: none; } you will find in user agent stylesheets,
are not included in the render tree as they will not appear in the rendered output.
Nodes with visibility: hidden applied are included in the render tree, as they do take up space.
As we have not given any directives to override the user agent default,
the script node in our code example above will not be included in the render tree.
(这句意思不懂,以后需要理解了再研究)
Each visible node has its CSSOM rules applied to it.
The render tree holds all the visible nodes with content and computed styles
-- matching up all the relevant styles to every visible node in the DOM tree,
and determining, based on the CSS cascade, what the computed styles are for each node.
The computed style tree, or render tree, construction starts with the root of the DOM tree,
traversing each visible node.
Tags that aren't going to be displayed, like the <head> and its children and
any nodes with display: none, such as the script { display: none; } you will find in user agent stylesheets,
are not included in the render tree as they will not appear in the rendered output.
Nodes with visibility: hidden applied are included in the render tree, as they do take up space.
As we have not given any directives to override the user agent default,
the script node in our code example above will not be included in the render tree.
(这句意思不懂,以后需要理解了再研究)
Each visible node has its CSSOM rules applied to it.
The render tree holds all the visible nodes with content and computed styles
-- matching up all the relevant styles to every visible node in the DOM tree,
and determining, based on the CSS cascade, what the computed styles are for each node.
Layout
The fourth step in the critical rending path is running layout on the render tree to compute the geometry of each node.
Layout is the process by which the width, height, and location of all the nodes in the render tree are determined,
plus the determination of the size and position of each object on the page.
Reflow is any subsequent size and position determination of any part of the page or the entire document.
Once the render tree is built, layout commences. The render tree identified which nodes are displayed (even if invisible) along with their computed styles, but not the dimensions or location of each node. To determine the exact size and location of each object, the browser starts at the root of the render tree and traverses it.
On the web page, most everything is a box. Different devices and different desktop preferences mean an unlimited number of differing viewport sizes. In this phase, taking the viewport size into consideration, the browser determines what the dimensions of all the different boxes are going to be on the screen. Taking the size of the viewport as its base, layout generally starts with the body, laying out the dimensions of all the body’s descendants, with each element's box model properties, providing placeholder space for replaced elements it doesn’t know the dimensions of, such as our image.
The first time the size and position of nodes are determined is called layout.
Subsequent recalculations of node size and locations are called reflows. In our example, suppose the initial layout occurs before the image is returned.
Since we didn't declare the size of our image, there will be a reflow once the image size is known.
Layout is the process by which the width, height, and location of all the nodes in the render tree are determined,
plus the determination of the size and position of each object on the page.
Reflow is any subsequent size and position determination of any part of the page or the entire document.
Once the render tree is built, layout commences. The render tree identified which nodes are displayed (even if invisible) along with their computed styles, but not the dimensions or location of each node. To determine the exact size and location of each object, the browser starts at the root of the render tree and traverses it.
On the web page, most everything is a box. Different devices and different desktop preferences mean an unlimited number of differing viewport sizes. In this phase, taking the viewport size into consideration, the browser determines what the dimensions of all the different boxes are going to be on the screen. Taking the size of the viewport as its base, layout generally starts with the body, laying out the dimensions of all the body’s descendants, with each element's box model properties, providing placeholder space for replaced elements it doesn’t know the dimensions of, such as our image.
The first time the size and position of nodes are determined is called layout.
Subsequent recalculations of node size and locations are called reflows. In our example, suppose the initial layout occurs before the image is returned.
Since we didn't declare the size of our image, there will be a reflow once the image size is known.
Paint
The last step in the critical rendering path is painting the individual nodes to the screen,
the first occurence of which is called the first meaningful paint.
In the painting or rasterization(光栅化) phase, the browser converts each box calculated in the layout phase to actual pixels on the screen.
Painting involves drawing every visual part of an element to the screen, including text, colors, borders, shadows,
and replaced elements like buttons and images. The browser needs to do this super quickly.
To ensure smooth scrolling and animation, everything occupying the main thread, including calculating styles, along with reflow and paint, must take the browser less than 16.67ms to accomplish.
At 2048 X 1536, the iPad has over 3,145,000 pixels to be painted to the screen. That is a lot of pixels that have to be painted very quickly.
To ensure repainting can be done even faster than the initial paint, the drawing to the screen is generally broken down into several layers.
If this occurs, then compositing is necessary.
Painting can break the elements in the layout tree into layers.
Promoting content into layers on the GPU (instead of the main thread on the CPU) improves paint and repaint performance.
There are specific properties and elements that instantiate a layer, including <video> and <canvas>,
and any element which has the CSS properties of opacity, a 3D transform, will-change, and a few others.
These nodes will be painted onto their own layer, along with their descendants,
unless a descendant necessitates(使成为必要) its own layer for one (or more) of the above reasons.
Layers do improve performance, but are expensive when it comes to memory management,
so should not be overused as part of web performance optimization strategies.
the first occurence of which is called the first meaningful paint.
In the painting or rasterization(光栅化) phase, the browser converts each box calculated in the layout phase to actual pixels on the screen.
Painting involves drawing every visual part of an element to the screen, including text, colors, borders, shadows,
and replaced elements like buttons and images. The browser needs to do this super quickly.
To ensure smooth scrolling and animation, everything occupying the main thread, including calculating styles, along with reflow and paint, must take the browser less than 16.67ms to accomplish.
At 2048 X 1536, the iPad has over 3,145,000 pixels to be painted to the screen. That is a lot of pixels that have to be painted very quickly.
To ensure repainting can be done even faster than the initial paint, the drawing to the screen is generally broken down into several layers.
If this occurs, then compositing is necessary.
Painting can break the elements in the layout tree into layers.
Promoting content into layers on the GPU (instead of the main thread on the CPU) improves paint and repaint performance.
There are specific properties and elements that instantiate a layer, including <video> and <canvas>,
and any element which has the CSS properties of opacity, a 3D transform, will-change, and a few others.
These nodes will be painted onto their own layer, along with their descendants,
unless a descendant necessitates(使成为必要) its own layer for one (or more) of the above reasons.
Layers do improve performance, but are expensive when it comes to memory management,
so should not be overused as part of web performance optimization strategies.
Compositing
When sections of the document are drawn in different layers, overlapping each other,
compositing is necessary to ensure they are drawn to the screen in the right order and
the content is rendered correctly.
As the page continues to load assets, reflows can happen (recall our example image that arrived late).
A reflow sparks a repaint and a re-composite.
compositing is necessary to ensure they are drawn to the screen in the right order and
the content is rendered correctly.
As the page continues to load assets, reflows can happen (recall our example image that arrived late).
A reflow sparks a repaint and a re-composite.
5. Interactivity
Once the main thread is done painting the page, you would think we would be "all set."
That isn't necessarily the case.
If the load includes JavaScript, that was correctly deferred, and only executed after the onload event fires,
the main thread might be busy, and not available for scrolling, touch, and other interactions.
Time to Interactive (TTI) is the measurement of how long it took from that first request
which led to the DNS lookup and SSL connection to when the page is interactive
-- interactive being the point in time after the First Contentful Paint when the page responds to user interactions
within 50ms.
If the main thread is occupied parsing, compiling, and executing JavaScript,
it is not available and therefore not able to responsd to user interactions in a timely (less than 50ms) fashion.
In our example, maybe the image loaded quickly, but perhaps the anotherscript.js file was 2MB
and our user's network connection was slow. In this case the user would see the page super quickly,
but wouldn't be able to scroll without jank until the script was downloaded, parsed and executed.
That is not a good user experience. Avoid occupying the main thread.
That isn't necessarily the case.
If the load includes JavaScript, that was correctly deferred, and only executed after the onload event fires,
the main thread might be busy, and not available for scrolling, touch, and other interactions.
Time to Interactive (TTI) is the measurement of how long it took from that first request
which led to the DNS lookup and SSL connection to when the page is interactive
-- interactive being the point in time after the First Contentful Paint when the page responds to user interactions
within 50ms.
If the main thread is occupied parsing, compiling, and executing JavaScript,
it is not available and therefore not able to responsd to user interactions in a timely (less than 50ms) fashion.
In our example, maybe the image loaded quickly, but perhaps the anotherscript.js file was 2MB
and our user's network connection was slow. In this case the user would see the page super quickly,
but wouldn't be able to scroll without jank until the script was downloaded, parsed and executed.
That is not a good user experience. Avoid occupying the main thread.
回流与重绘
回流
当 render tree 的部分(或全部) 因为元素的 规模尺寸、布局,隐藏等改变而需要重新构建,这就称为回流(reflow)。
每个页面至少需要一次回流,就是在页面第一次加载的时候。
在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,
完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。
回流必将引起重绘,而重绘不一定会引起回流。
每个页面至少需要一次回流,就是在页面第一次加载的时候。
在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,
完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。
回流必将引起重绘,而重绘不一定会引起回流。
重绘
当 render tree 中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不影响布局,
比如 background-color,则就叫称为重绘。
比如 background-color,则就叫称为重绘。
回流何时发生
当页面布局和元素几何属性改变时就需要回流。
- 页面渲染初始化
- 增加或删除可见的DOM元素
- 元素位置改变
- 元素尺寸改变,边距、填充、边框、宽度和高度
元素内容改变导致尺寸变化,比如文本改变或者图片大小改变而引起的计算值宽度和高度改变 - 页面窗口发生变化,也就是resize时
浏览器的
回流与重绘队列
回流与重绘队列
浏览器会维护一个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,
浏览器就会 flush 队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。
浏览器就会 flush 队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。
强制浏览器提前 flush 队列的代码
导致浏览器同步计算 style 与 layou 的 JS 代码
导致浏览器同步计算 style 与 layou 的 JS 代码
Element
盒子宽高相关属性或方法
elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight, elem.offsetParent
elem.clientLeft, elem.clientTop, elem.clientWidth, elem.clientHeight
elem.getClientRects(), elem.getBoundingClientRect()
elem.clientLeft, elem.clientTop, elem.clientWidth, elem.clientHeight
elem.getClientRects(), elem.getBoundingClientRect()
getClientRects vs getBoundingClientRect
Element.getClientRects()
返回一个指向客户端中每一个盒子的边界矩形的矩形集合。
lement.getBoundingClientRect()
返回元素的大小及其相对于视口的位置。
请求上面的一些属性的时候,浏览器为了给你最精确的值,需要flush队列,因为队列中可能会有影响到这些值的操作。
即使你获取元素的布局和样式信息跟最近发生或改变的布局信息无关,浏览器都会强行刷新渲染队列。
即使你获取元素的布局和样式信息跟最近发生或改变的布局信息无关,浏览器都会强行刷新渲染队列。
滚动相关
elem.scrollBy(), elem.scrollTo()
elem.scrollIntoView(), elem.scrollIntoViewIfNeeded()
elem.scrollWidth, elem.scrollHeight
elem.scrollLeft, elem.scrollTop also, setting them
elem.scrollIntoView(), elem.scrollIntoViewIfNeeded()
elem.scrollWidth, elem.scrollHeight
elem.scrollLeft, elem.scrollTop also, setting them
focus()
elem.focus() can trigger a double forced layout
window.getComputedStyle()
window.getComputedStyle() will typically force style recalc
window.getComputedStyle() will force layout, in some cases
window.getComputedStyle() will force layout, in some cases
let style = window.getComputedStyle(element, [pseudoElt]);
window
window.scrollX, window.scrollY
window.innerHeight, window.innerWidth
window.innerHeight, window.innerWidth
表单
inputElem.focus()
inputElem.select(), textareaElem.select()
inputElem.select(), textareaElem.select()
Mouse events
mouseEvt.layerX, mouseEvt.layerY,
mouseEvt.offsetX, mouseEvt.offsetY
mouseEvt.offsetX, mouseEvt.offsetY
Range
range.getClientRects(), range.getBoundingClientRect()
contenteditable
Lots & lots of stuff, …including copying an image to clipboard
如何减少回流、重绘
减少回流、重绘其实就是需要减少对render tree的操作(合并多次多 DOM 和 样式 的修改),并减少对一些style信息的请求
批量修改 css
直接改变className,如果动态改变样式,则使用 cssText 合并 css 修改:
// 不好的写法
var left = 1;
var top = 1;
el.style.left = left + "px";
el.style.top = top + "px";
// 比较好的写法
el.className += " className1";
// 比较好的写法
el.style.cssText += "left: " + left + "px; top: " + top + "px;";
// 不好的写法
var left = 1;
var top = 1;
el.style.left = left + "px";
el.style.top = top + "px";
// 比较好的写法
el.className += " className1";
// 比较好的写法
el.style.cssText += "left: " + left + "px; top: " + top + "px;";
批量修改 dom 元素,
让要操作的元素进行”离线处理”,
处理完后一起更新
让要操作的元素进行”离线处理”,
处理完后一起更新
a) 使用 DocumentFragment 进行缓存操作,引发一次回流和重绘;
b) 使用 display:none 技术,只引发两次回流和重绘;
c) 使用 cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
var dupNode = node.cloneNode(deep);
replacedNode = parentNode.replaceChild(newChild, oldChild);
b) 使用 display:none 技术,只引发两次回流和重绘;
c) 使用 cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
var dupNode = node.cloneNode(deep);
replacedNode = parentNode.replaceChild(newChild, oldChild);
减少访问会引起浏览器flush队列的属性,
如果确实要访问,利用缓存
如果确实要访问,利用缓存
让元素脱离文档流,减少回流的 Render Tree的规模
Perceived performance
Relevant measurements
first meaningful paint (FMP)
when content appears on the screen that is actually meaningful;
largest contentful paint (LCP)
definited in the Largest Contentful Paint API,
reports the render time of the largest content element visible in the viewport.
reports the render time of the largest content element visible in the viewport.
time to interactive (TTI)
render start
DOM interactive
speed index
it measures the average time for pixels on the visible screen to be painted.
Improving perceived performance
Minimize initial load
Prevent jumping content and other reflows
Avoid font file delays
Make fallback fonts the same size and weight so that when fonts load the page change is less noticeable.
Interactive elements are interactive
Make task initiators appear more interactive
Making a content request on keydown rather than waiting for keyup can shave 200ms off the perceived load of the content.
Adding an interesting but unobtrusive 200ms animation to that keyup even can reduce another 200ms of the perceived load.
You're not saving 400ms of time, but the user doesn't feel like they're waiting for content until, well, until they're waiting for content.
Adding an interesting but unobtrusive 200ms animation to that keyup even can reduce another 200ms of the perceived load.
You're not saving 400ms of time, but the user doesn't feel like they're waiting for content until, well, until they're waiting for content.
By turning as much of the download, render and wait time into active phases and reducing any passive waiting, even if the objective measurements stay the same, the user will feel like the content downloaded, rendered, and responded more quickly.
性能基础
最佳实践
优化首屏渲染路径
使用 resource hints
例如 rel=preconnect,
rel=dns-prefetch,
rel=prefetch,
and rel=preload
例如 rel=preconnect,
rel=dns-prefetch,
rel=prefetch,
and rel=preload
链接类型
preconnect
向浏览器提供提示,建议浏览器提前打开链接网站的连接,而不会泄露任何私人信息或下载任何内容,
以便在跟随链接时可以更快地获取链接内容。
以便在跟随链接时可以更快地获取链接内容。
dns-prefetch
提示浏览器该资源是被需要的。允许浏览器 在用户点击链接之前 进行DNS查询和协议握手。
prefetch
提示浏览器提前加载链接的资源,因为它可能会被用户请求。
从Firefox 44开始,考虑了crossorigin属性的值,从而可以进行匿名预取。
注意:Link Prefetch FAQ详细说明了可以预取的链接以及替代方法。
从Firefox 44开始,考虑了crossorigin属性的值,从而可以进行匿名预取。
注意:Link Prefetch FAQ详细说明了可以预取的链接以及替代方法。
preload
告诉浏览器下载资源,因为在当前导航期间稍后将需要该资源。
压缩资源
减少请求
只加载当前页面需要的资源
在你的服务器(或者CDN)上使用 HTTP/2协议
HTTP2 的性能优点
- 并行的请求能在同一个链接中处理,移除了HTTP/1.x中顺序和阻塞的约束。
- 压缩了headers。因为headers在一系列请求中常常是相似的,这样移除了重复和传输重复数据的成本。
使用CDN托管静态资源
It is also crucial to realize what is really important to your users.
It might not be absolute timing, but user perception.
It might not be absolute timing, but user perception.
速效方案
CSS
Llinking CSS with a tradional link tag with rel="stylesheet" is synchronous and blocks rendering.
Optimize the rendering of your page by removing blocking CSS.
To load CSS asynchronously one can simpy set the media type to print and then change to all once loaded.
The following snippet includes an onload attribute, requiring Javascript,
so it is important to include a noscript tag with a traditional fallback.
<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/path/to/my.css"></noscript>
noscript 不清晰,以后有需要了再详尽研究
Optimize the rendering of your page by removing blocking CSS.
To load CSS asynchronously one can simpy set the media type to print and then change to all once loaded.
The following snippet includes an onload attribute, requiring Javascript,
so it is important to include a noscript tag with a traditional fallback.
<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/path/to/my.css"></noscript>
noscript 不清晰,以后有需要了再详尽研究
The downside with this approach is the flash of unstyled text (FOUT.)
The simplist way to address this is by inlining CSS that is required for any content that is rendered above the fold, or what you see in the browser viewport before scrolling. These styles will improve perceived performance as the CSS does not require a file request.
<style type="text/css">
// Insert your CSS here
</style>
The simplist way to address this is by inlining CSS that is required for any content that is rendered above the fold, or what you see in the browser viewport before scrolling. These styles will improve perceived performance as the CSS does not require a file request.
<style type="text/css">
// Insert your CSS here
</style>
JS
- Avoid Javascript blocking by using the async or defer attributes,
- or link javascript assets after the page's DOM elements.
网页字体
EOT and TTF formats are not compressed by default.
Apply compression such as GZIP or Brotli for these file types.
Use WOFF and WOFF2. These formats have compression built in.
Within @font-face use font-display: swap.
By using font display swap the browser will not block rendering and will use the backup system fonts that are defined.
Optimiize font weight to match the web font as closely as possible.
Apply compression such as GZIP or Brotli for these file types.
Use WOFF and WOFF2. These formats have compression built in.
Within @font-face use font-display: swap.
By using font display swap the browser will not block rendering and will use the backup system fonts that are defined.
Optimiize font weight to match the web font as closely as possible.
Icon web fonts
If possible avoid icon web fonts and use compressed SVGs.
(为啥要避免使用字体图标而使用 svg 文档里没说,以后需要了解了再研究)
To further optimize inline your SVG data within HTML markup to avoid HTTP requests.
(为啥要避免使用字体图标而使用 svg 文档里没说,以后需要了解了再研究)
To further optimize inline your SVG data within HTML markup to avoid HTTP requests.
关键渲染路径
(首屏/必要元素渲染路径)
Critical rendering path
(首屏/必要元素渲染路径)
Critical rendering path
CRP 总述
CRP 简介
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 critical rendering path includes the Document Object Model (DOM),
CSS Object Model (CSSOM), render tree
and layout.
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 critical rendering path includes the Document Object Model (DOM),
CSS Object Model (CSSOM), render tree
and layout.
- critical - absolutely needed ( initial view )
- render - display or show (in our case our webpages are "rendered" when they can be seen by a user)
- path - the chain of events that lead to our webpage being displayed in a browser
- initial view - also known as "above the fold", the initial view is the part of a webpage visible to a user before they scroll
DOM / CSSOM /
Render Tree / Layout /
Paint 的相互关系
Render Tree / Layout /
Paint 的相互关系
The document object model is created as the HTML is parsed.
The HTML may request JavaScript, which may, in turn, alter the DOM.
The HTML includes or makes requests for styles, which in turn builds the CSS object model.
The browser engine combines the two to create the Render Tree.
Layout determines the size and location of everything on the page.
Once layout is determined, pixels are painted to the screen.
The HTML may request JavaScript, which may, in turn, alter the DOM.
The HTML includes or makes requests for styles, which in turn builds the CSS object model.
The browser engine combines the two to create the Render Tree.
Layout determines the size and location of everything on the page.
Once layout is determined, pixels are painted to the screen.
优化 CRP 的意义
Optimizing the critical rendering path improves the time to first render.
Understanding and optimizing the critical rendering path is important to
ensure reflows and repaints can happen at 60 frames per second,
to ensure performant user interactions and avoid jank.
Understanding and optimizing the critical rendering path is important to
ensure reflows and repaints can happen at 60 frames per second,
to ensure performant user interactions and avoid jank.
CRP 流程 / PATH
Web performance includes the server requests and responses, loading, scripting, rendering, layout,
and the painting of the pixels to the screen.
A request for a web page or app starts with an HTML request.
The server returns the HTML - response headers and data.
The browser then begins parsing the HTML, converting the received bytes to the DOM tree.
The browser initiates requests every time it finds links to external resources,
be they stylesheets, scripts, or embedded image references.
Some requests are blocking, which means the parsing of the rest of the HTML is halted until the imported asset is handled.
The browser continues to parse the HTML making requests and building the DOM, until it gets to the end,
at which point it constructs the CSS object model.
With the DOM and CSSOM complete, the browser builds the render tree, computing the styles for all the visible content
.
After the render tree is complete, layout occurs, defining the location and size of all the render tree elements.
Once complete, the page is rendered, or 'painted' on the screen.
and the painting of the pixels to the screen.
A request for a web page or app starts with an HTML request.
The server returns the HTML - response headers and data.
The browser then begins parsing the HTML, converting the received bytes to the DOM tree.
The browser initiates requests every time it finds links to external resources,
be they stylesheets, scripts, or embedded image references.
Some requests are blocking, which means the parsing of the rest of the HTML is halted until the imported asset is handled.
The browser continues to parse the HTML making requests and building the DOM, until it gets to the end,
at which point it constructs the CSS object model.
With the DOM and CSSOM complete, the browser builds the render tree, computing the styles for all the visible content
.
After the render tree is complete, layout occurs, defining the location and size of all the render tree elements.
Once complete, the page is rendered, or 'painted' on the screen.
DOM / CSSOM /
Render Tree / Layout /
Paint 详细介绍
Render Tree / Layout /
Paint 详细介绍
Document Object Model
DOM construction is incremental.
The HTML response turns into tokens which turns into nodes which turn into the DOM Tree.
A single DOM node starts with a startTag token and ends with an endTag token.
Nodes contain all relevant information about the HTML element.
The information is described using tokens.
Nodes are connected into a DOM tree based on token hierarchy.
If another set of startTag and endTag tokens come between a set of startTag and endTags,
you have a node inside a node, which is how we define the hierarchy of the DOM tree.
The greater the number of nodes, the longer the following events in the critical rendering path will take.
Measure! A few extra nodes won't make a difference, but divitis can lead to jank.
The HTML response turns into tokens which turns into nodes which turn into the DOM Tree.
A single DOM node starts with a startTag token and ends with an endTag token.
Nodes contain all relevant information about the HTML element.
The information is described using tokens.
Nodes are connected into a DOM tree based on token hierarchy.
If another set of startTag and endTag tokens come between a set of startTag and endTags,
you have a node inside a node, which is how we define the hierarchy of the DOM tree.
The greater the number of nodes, the longer the following events in the critical rendering path will take.
Measure! A few extra nodes won't make a difference, but divitis can lead to jank.
CSS Object Model
The DOM contains all the content of the page.
The CSSOM contains all the styles of the page; information on how to style that DOM.
The CSSOM contains all the styles of the page; information on how to style that DOM.
CSSOM is similar the the DOM, but different.
While the DOM construction is incremental, CSSOM is not.
While the DOM construction is incremental, CSSOM is not.
CSS is render blocking: the browser blocks page rendering until it receives and processes all of the CSS.
CSS is render blocking because rules can be overwritten, so the content can't be rendered until the CSSOM is complete. CSS has its own set of rules for identifying valid tokens.
Remember the C in CSS stands for 'Cascade'. CSS rules cascade down.
As the parser converts tokens to nodes, with descendants of nodes inheriting styles.
The incremental processing features don't apply to CSS like they do with HTML,
because subsequent rules may override previous ones.
The CSS object model gets built as the CSS is parsed,
but can't be used to build the render tree until it is completely parsed
because styles that are going to be overwritten with later parsing should not be rendered to the screen.
In terms of selector performance, less specific selectors are faster than more specific ones.
For example, .foo {} is faster than .bar .foo {} because when the browser finds .foo, in the second scenario,
it has to walk up the DOM to check if .foo has an ancestor .bar.
The more specific tag requires more work from the browser, but this penalty is not likely worth optimizing.
If you measure the time it takes to parse CSS, you'll be amazed at how fast browsers truly are.
The more specific rule is more expensive because it has to traverse more nodes in the DOM tree -
but that extra expense is generally minimal.
Measure first. Optimize as needed.
Specificity is likely not your low hanging fruit.
When it comes to CSS, selector performance optimization, improvements will only be in microseconds.
There are other ways to optimize CSS,
such as minification,
and separating defered CSS into non-blocking requests by using media queries.
Remember the C in CSS stands for 'Cascade'. CSS rules cascade down.
As the parser converts tokens to nodes, with descendants of nodes inheriting styles.
The incremental processing features don't apply to CSS like they do with HTML,
because subsequent rules may override previous ones.
The CSS object model gets built as the CSS is parsed,
but can't be used to build the render tree until it is completely parsed
because styles that are going to be overwritten with later parsing should not be rendered to the screen.
In terms of selector performance, less specific selectors are faster than more specific ones.
For example, .foo {} is faster than .bar .foo {} because when the browser finds .foo, in the second scenario,
it has to walk up the DOM to check if .foo has an ancestor .bar.
The more specific tag requires more work from the browser, but this penalty is not likely worth optimizing.
If you measure the time it takes to parse CSS, you'll be amazed at how fast browsers truly are.
The more specific rule is more expensive because it has to traverse more nodes in the DOM tree -
but that extra expense is generally minimal.
Measure first. Optimize as needed.
Specificity is likely not your low hanging fruit.
When it comes to CSS, selector performance optimization, improvements will only be in microseconds.
There are other ways to optimize CSS,
such as minification,
and separating defered CSS into non-blocking requests by using media queries.
media queries 部分 可查看 css 脑图:
Render Tree
The render tree captures both the content and the styles:
the DOM and CSSOM trees are combined into the render tree.
To construct the render tree, the browser checks every node,
starting from root of the DOM tree, and determine which CSS rules are attached.
The render tree only captures visible content.
The head section (generally) doesn't contain any visible information,
and is therefore not included in the render tree.
If there's a display: none; set on an element, neither it, nor any of its descendants, are in the render tree.
the DOM and CSSOM trees are combined into the render tree.
To construct the render tree, the browser checks every node,
starting from root of the DOM tree, and determine which CSS rules are attached.
The render tree only captures visible content.
The head section (generally) doesn't contain any visible information,
and is therefore not included in the render tree.
If there's a display: none; set on an element, neither it, nor any of its descendants, are in the render tree.
Layout
Once the render tree is built, layout becomes possible.
Layout is dependent on the size of screen.
The layout step determines where and how the elements are positioned on the page,
determining the width and height of each element, and where they are in relation to each other.
What is the width of an element?
Block level elements, by definition, have a default width of 100% of the width of their parent.
An element with a width of 50%, will be half of the width of its parent.
Unless otherwise defined, the body has a width of 100%, meaning it will be 100% of the width of the viewport.
This width of the device impacts layout.
The viewport meta tag defines the width of the layout viewport, impacting the layout.
Without it, the browser uses the default viewport width,
which on by-default full screen browsers is generally 960px.
On by-default full screen browsers, like your phone's browser,
by setting <meta name="viewport" content="width=device-width">,
the width will be the width of the device instead of the default viewport width.
The device-width changes when a user rotates their phone between landscape and portrait mode.
Layout happens every time a device is rotated or browser is otherwise resized.
Layout performance is impacted by the DOM -- the greater the number of nodes, the longer layout takes.
Layout can become a bottleneck, leading to jank if required during scrolling or other animations.
While a 20ms layout on load or orientation change may be fine, it will lead to jank on animation or scroll.
Any time the render tree is modified, such as by added nodes, altered content, or updated box model styles on a node,
layout occurs.
To reduce the frequency and duration of layout events, batch updates and avoid animating box model properties.
Layout is dependent on the size of screen.
The layout step determines where and how the elements are positioned on the page,
determining the width and height of each element, and where they are in relation to each other.
What is the width of an element?
Block level elements, by definition, have a default width of 100% of the width of their parent.
An element with a width of 50%, will be half of the width of its parent.
Unless otherwise defined, the body has a width of 100%, meaning it will be 100% of the width of the viewport.
This width of the device impacts layout.
The viewport meta tag defines the width of the layout viewport, impacting the layout.
Without it, the browser uses the default viewport width,
which on by-default full screen browsers is generally 960px.
On by-default full screen browsers, like your phone's browser,
by setting <meta name="viewport" content="width=device-width">,
the width will be the width of the device instead of the default viewport width.
The device-width changes when a user rotates their phone between landscape and portrait mode.
Layout happens every time a device is rotated or browser is otherwise resized.
Layout performance is impacted by the DOM -- the greater the number of nodes, the longer layout takes.
Layout can become a bottleneck, leading to jank if required during scrolling or other animations.
While a 20ms layout on load or orientation change may be fine, it will lead to jank on animation or scroll.
Any time the render tree is modified, such as by added nodes, altered content, or updated box model styles on a node,
layout occurs.
To reduce the frequency and duration of layout events, batch updates and avoid animating box model properties.
Paint
The last step in painting the pixels to the screen.
Once the render tree is created and layout occurs, the pixels can be painted to the screen.
Onload, the entire screen is painted.
After that, only impacted areas of the screen will be repainted,
as browsers are optimized to repaint the minimum area required.
Paint time depends on what kind of updates are being applied to the render tree.
While painting is a very fast process, and therefore likely not the most impactful place to focus on in improving performance,
it is important to remember to allow for both layout and re-paint times when measuring how long an animation frame may take.
The styles applied to each node increase the paint time, but removing style that increases the paint by 0.001ms may not
give you the biggest bang for your optimization buck.
Remember to measure first. Then you can determine whether it should be an optimization priority.
Once the render tree is created and layout occurs, the pixels can be painted to the screen.
Onload, the entire screen is painted.
After that, only impacted areas of the screen will be repainted,
as browsers are optimized to repaint the minimum area required.
Paint time depends on what kind of updates are being applied to the render tree.
While painting is a very fast process, and therefore likely not the most impactful place to focus on in improving performance,
it is important to remember to allow for both layout and re-paint times when measuring how long an animation frame may take.
The styles applied to each node increase the paint time, but removing style that increases the paint by 0.001ms may not
give you the biggest bang for your optimization buck.
Remember to measure first. Then you can determine whether it should be an optimization priority.
Optimizing for CRP
Improve page load speed by prioritizing which resources get loaded, controlling the order in which they are loaded, and reducing the file sizes of those resources.
Performance tips
减少首屏 http 请求
Images
1.Only show those one or two which are in the initial view.
The rest can be deferred or lazy loaded.
2.Base 64 encoded the logo and the first image
The rest can be deferred or lazy loaded.
2.Base 64 encoded the logo and the first image
defer images
A deferred image is downloaded after the initial page load
Images not initially visible on a page (below the fold) can be deferred allowing what is visible to load faster
Images not initially visible on a page (below the fold) can be deferred allowing what is visible to load faster
Deferring images
without lazy loading or jQuery
without lazy loading or jQuery
The truth is that lazy loading images is just a more complicated way of deferring images.
To get back to basics we will be talking about deferring images without lazy loading.
But let's first define the stuff that lazy loading is actually doing.
In the four things above, only one of them is the deferring of images.
To get back to basics we will be talking about deferring images without lazy loading.
But let's first define the stuff that lazy loading is actually doing.
- Observing a scroll position
- Monitoring scroll position
- Reacting to a scroll position
- deferring images
In the four things above, only one of them is the deferring of images.
the deferring images part
html
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">
js
function init() {
let imgDefer = document.getElementsByTagName("img");
for (let i = 0; i < imgDefer.length; i++) {
let curImg = imgDefer[i];
let curDataSrc = curImg.getAttribute("data-src");
if (curDataSrc) {
curImg.setAttribute("src", curDataSrc);
}
}
}
window.onload = init;
let imgDefer = document.getElementsByTagName("img");
for (let i = 0; i < imgDefer.length; i++) {
let curImg = imgDefer[i];
let curDataSrc = curImg.getAttribute("data-src");
if (curDataSrc) {
curImg.setAttribute("src", curDataSrc);
}
}
}
window.onload = init;
Javascript files
Only initially load the ones that are critical to show the top part of our webpage,
and the other javascript files can be deferred.
and the other javascript files can be deferred.
CSS files
- By combining some of your external CSS files you can reduce the amount of files needed to download.
- You can also inline some of your CSS into your html.
减小请求资源体积
压缩 imges, css files, js files
合理设置缓存
设置 cache-control,expires,以及 E-tag 都是不错的。
不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。
其中一个解决防范是在文件名字后面加一个版本号
不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。
其中一个解决防范是在文件名字后面加一个版本号
使用 CDN
CDN会根据你的网络状况,替你挑选最近的一个具有缓存内容的节点为你提供资源,因此可以减少加载时间
参考文章
https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path
https://varvy.com/pagespeed/critical-render-path.html
https://juejin.im/post/5b88ddca6fb9a019c7717096
常考知识点
js 的 async 与 defer attribute
async
For classic scripts, if the async attribute is present, then the classic script will be fetched in parallel to parsing and evaluated as soon as it is available.
For module scripts, if the async attribute is present, then the module script and all its dependencies will be fetched in parallel to parsing, and the module script will be evaluated as soon as it is available.
This attribute allows the elimination of parser-blocking JavaScript where the browser would have to load and evaluate scripts before continuing to parse. defer has a similar effect in this case.
This is a boolean attribute: the presence of a boolean attribute on an element represents the true value, and the absence of the attribute represents the false value.
For module scripts, if the async attribute is present, then the module script and all its dependencies will be fetched in parallel to parsing, and the module script will be evaluated as soon as it is available.
This attribute allows the elimination of parser-blocking JavaScript where the browser would have to load and evaluate scripts before continuing to parse. defer has a similar effect in this case.
This is a boolean attribute: the presence of a boolean attribute on an element represents the true value, and the absence of the attribute represents the false value.
defer
这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行。
Scripts with the defer attribute will prevent the DOMContentLoaded event from firing until the script has loaded and finished evaluating.
This attribute allows the elimination of parser-blocking JavaScript where the browser would have to load and evaluate scripts before continuing to parse. async has a similar effect in this case.
Scripts with the defer attribute will prevent the DOMContentLoaded event from firing until the script has loaded and finished evaluating.
This attribute allows the elimination of parser-blocking JavaScript where the browser would have to load and evaluate scripts before continuing to parse. async has a similar effect in this case.
async 是 HTML5 规范的新特性,优先级比 defer 高。
部分不支持 async 的低版本浏览器会将其降级为 defer。
部分不支持 async 的低版本浏览器会将其降级为 defer。
浏览器在解析 HTML 文档时,不论 <script> 标签是否有 defer 或 async 属性,均会立即下载其 src 指定的 JS 文件。
有 async 或者 defer 属性的标签,JS 文件的下载过程均不会阻塞 HTML 文档的解析和渲染。
有 async 或者 defer 属性的标签,JS 文件的下载过程均不会阻塞 HTML 文档的解析和渲染。
async 和 defer 的区别在 JS 文件的执行时机上
async
工作原理与 JS 异步逻辑类似,即“异步下载,同步执行”。
下载完成后立即执行,执行期间浏览器将暂停 HTML 文档的解析。
下载完成后立即执行,执行期间浏览器将暂停 HTML 文档的解析。
执行是无序的
defer
在文档完成解析后,触发 DOMContentLoaded 事件前执行。
所以这里 defer 的意思是延迟 JS 的执行时机。
所以这里 defer 的意思是延迟 JS 的执行时机。
执行顺序和 <script> 标签在HTML文档中的顺序保持一致
async 和 defer 的应用场景
defer
对于需要与 HTML 文档同步加载并且对执行顺序敏感的 JS 文件而言,
为其 <script> 标签添加 defer 属性并且置于 <head> 中
可以提前触发 JS 文件的下载,充分发挥浏览器并行请求的优势。
为其 <script> 标签添加 defer 属性并且置于 <head> 中
可以提前触发 JS 文件的下载,充分发挥浏览器并行请求的优势。
async
适用于按需加载、逻辑独立的异步 JS 模块
(事实上,对于动态创建的 <script> 标签,其 async 属性默认为 true)。
(事实上,对于动态创建的 <script> 标签,其 async 属性默认为 true)。
CDN
CDN的全称是Content Delivery Network,即内容分发网络。
CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,
使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。
CDN的关键技术主要有内容存储和分发技术。
CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,
使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。
CDN的关键技术主要有内容存储和分发技术。
0 条评论
下一页
为你推荐
查看更多