Article directory
- Front-end monitoring performance indicators
-
- Performance
- W3C Level 1
-
- compatibility
- conventional usage
- Precautions
-
- 1. Calculate the HTML document request using Nav Timing
- 2. To calculate static resources, use getEntriesByType('resource') instead of getEntries()
- 3. SecureConnectionStart problem
- 4. Cross-domain resource setting response header Timing-Allow-Origin
- 5. Pay attention to the meaning of attribute value 0
- 6、304
- W3C Level 2
- Report data
- Summarize
- reference
Front-end monitoring performance indicators
Performance
Stage indicators
field | describe | Calculation | Remark |
---|---|---|---|
unload | Time-consuming to unload the previous page | unloadEventEnd - unloadEventStart | When the previous page was unloaded, it may have listened to unload to do some data collection, which will affect the page jump |
redirect | Time consuming to redirect | redirectEnd - redirectStart | Excessive redirection affects performance |
appCache | Caching takes time | domainLookupStart - fetchStart | |
dns | Time-consuming DNS resolution | domainLookupEnd - domainLookupStart | |
tcp | TCP connection time-consuming | connectEnd - connectStart | |
ssl | SSL secure connection takes time | connectEnd - secureConnectionStart | Only works under HTTPS |
ttfb | Time to First Byte (TTFB), network request time-consuming | responseStart - requestStart | |
response | Time-consuming data transfer | responseEnd - responseStart | |
dom | Interactive DOM parsing time-consuming | domInteractive - responseEnd | Interactive content |
dom2 | Remaining DOM parsing time-consuming | domContentLoadedEventStart - domInteractive | DOMContentLoaded All DOM elements are loaded (except async script) |
DCL | Time-consuming DOMContentLoaded event | domContentLoadedEventEnd - domContentLoadedEventStart | document.addEventListener(‘DOMContentLoaded’, cb) |
resources | Time-consuming resource loading | loadEventStart - domContentLoadedEventEnd | Time from complete DOM (DOMContentLoaded) to resource loading (window.onLoad) |
onLoad | time-consuming onLoad event | loadEventEnd - loadEventStart |
Key Performance Indicators
field | describe | Calculation | Remark |
---|---|---|---|
firstbyte | First package time | responseStart - domainLookupStart | |
fpt | First Paint Time, first rendering time/white screen time | responseEnd - fetchStart | The time difference from the start of the request until the browser starts parsing the first batch of HTML document bytes |
tti | Time to Interact, first interactive time | domInteractive - fetchStart | The browser completes all HTML parsing and completes DOM construction, at which point the browser starts loading resources |
ready | HTML loading completion time, that is, DOM Ready time | domContentLoadedEventEnd - fetchStart | If the page has synchronously executed JS, synchronous JS execution time = ready - tti |
load | page full load time | loadEventStart - fetchStart | load = first rendering time + DOM parsing time + synchronous JS execution + resource loading time |
Applets
field | describe | Calculation | Remark |
---|---|---|---|
fpt | First Paint Time, the first rendering time | onShow (first page) - onLaunch (app) | The time between the applet's onLaunch and the first page's onShow |
W3C Level 1
compatibility
conventional usage
- Calculations main page
const t = performance.timing;
const pageloadtime = t.loadEventStart - t.navigationStart,
dns = t.domainLookupEnd - t.domainLookupStart,
tcp = t.connectEnd - t.connectStart,
ttfb = t.responseStart - t.navigationStart;
- Calculate Page Resources
const r0 = performance.getEntriesByType('resource')[0];
const loadtime = r0.duration,
dns = r0.domainLookupEnd - r0.domainLookupStart,
tcp = r0.connectEnd - r0.connectStart,
ttfb = r0.responseStart - r0.startTime;
Precautions
1. Calculate the HTML document request using Nav Timing
Get home page html data, should be used performance.timing
instead performance.getEntriesByType('resource')[0]
.
performance.getEntriesByType('resource')
Indicates all static resource information referenced in the current HTML document, excluding its own HTML information.
If it does not currently contain any static resources, then performance.getEntriesByType('resource') === []
using [0].xx
will report an error.
2. To calculate static resources, use getEntriesByType('resource') instead of getEntries()
getEntries()
Contains the following six types
- navigation
- resource
- mark
- measure
- paint
- frame
In older browsers, getEntries()
usually only resource
the type is equivalent to getEntriesByType('resource')
.
Because navigation
is Navigation Timing 2
a specification, older browsers do not support it. And mark
and measure
are User Timing
user- defined types.
The last two are implemented by even fewer browsers for now (2020).
All the use of getEntries()
to retrieve static resources requires filtering for several other types, getEntriesByType('resource')
which is clear.
3. SecureConnectionStart problem
secureConnectionStart
Used to measure the time spent SSL协商
in , there are three possible values
- undefined, the browser does not support this attribute;
- 0, not using HTTPS;
- timestamp timestamp, using HTTPS
There is a bug in the very old version of chrome. When the resource is retrieved to reuse the established HTTPS channel, it is secureConnectionStart
set to 0. According to the standard, it should be set to timestamp.
Unsupported and unused situations should be avoided when taking values
const r0 = performance.getEntriesByType('resource')[0];
if ( r0.secureConnectionStart ) {
const ssl = r0.connectEnd - r0.secureConnectionStart;
}
4. Cross-domain resource setting response header Timing-Allow-Origin
When obtaining page resource time details, there are cross-domain restrictions. By default, the following attributes of cross-origin resources will be set to 0
redirectStart
redirectEnd
domainLookupStart
domainLookupEnd
connectStart
connectEnd
secureConnectionStart
requestStart
responseStart
- For controllable cross-domain resources such as your own home
CDN
,Timing-Allow-Origin
the response header origins must at least set the domain name of the main page to allow access to resource time. - Generally external public resources are set to
Timing-Allow-Origin: *
. - For third-party uncontrollable resources and no
Timing-Allow-Origin
header , these invalid data should be filtered out.
If not Timing-Allow-Origin
set
- Without filtering, the reported data will be much better than the actual usage of the user;
- After filtering, the resources on the cross-domain CDN cannot report data, so the advantages of being on the CDN cannot be analyzed.
// Resource Timing
const r0 = performance.getEntriesByType('resource')[0],
loadtime = r0.duration;
// 只要选取上述一个属性(除了secureConnectionStart)进行判断即可
if ( r0.requestStart ) {
const dns = r0.domainLookupEnd - r0.domainLookupStart,
tcp = r0.connectEnd - r0.connectStart,
ttfb = r0.responseStart - r0.startTime;
}
let ssl = 0; // 默认为 0,当然也可以在数据库层面去做
// 使用了 HTTPS 在计算
if ( r0.secureConnectionStart ) {
ssl = r0.connectEnd - r0.secureConnectionStart;
}
5. Pay attention to the meaning of attribute value 0
above we know
- secureConnectionStart === 0 when not using HTTPS
Timing-Allow-Origin
When cross-domain and the correct is not set , there are several attribute values of 0
- DNS resolution time
domainLookupEnd - domainLookupStart === 0
- For resources under the same domain name as HTML, the DNS time may be 0, because the browser will cache the IP of the currently resolved domain name;
- The browser pre-resolves the DNS and caches it,
<link rel="dns-prefetch" href="//cross-domain.com" />
.
- TCP connection establishment time
connectEnd – connectStart === 0
- For example, the browser can establish 6 independent TCP connections with each host at the same time, then the TCP of the first 6 resources is non-zero, and the remaining
keep-alive
channel multiplexing TCP time is 0
- SSL
connectEnd – secureConnectionStart === 0
- Same as TCP
- Not using HTTPS
In short, there are many scenarios for zero, pay attention to the distinction.
- not support
- Unused
- reuse
- cache
- Not displayed for security reasons
- …
6、304
There is a bug in the very old chrome version, when 200 is Timing-Allow-Origin
not set at 304,
many of the above properties cannot be set to timestamp type but 0.
Then here comes the problem
- You filtered 304 cases in #4 and only counted 200 cases. It is well known that 304 caching technical details are better than non-caching 200 cases.
This will lower your average stat performance. - If you don't filter, you will get better performance statistics than 304.
In this case, there is no way to distinguish for the time being. Fortunately, chrome fixed it in version 37.
PS: The iframe and the document environment are isolated from each other, you can get the contentWindow.performance of the iframe to get it.
W3C Level 2
compatibility
usage
PerformanceNavigationTiming
- Replace
performance.timing
(currently high compatibility, still available, may be deprecated in the future).
const pageNav = performance.getEntriesByType('navigation')[0];
- PerformanceNavigationTiming uses High-Resolution Time, and the time precision can reach several decimal places in milliseconds.
{
"name": "https://developer.mozilla.org/zh-CN/docs/Web/Performance",
"entryType": "navigation",
"startTime": 0,
"duration": 13636.144999996759,
"initiatorType": "navigation",
"nextHopProtocol": "h2",
"workerStart": 0,
"redirectStart": 0,
"redirectEnd": 0,
"fetchStart": 8.684999993420206,
"domainLookupStart": 8.684999993420206,
"domainLookupEnd": 8.684999993420206,
"connectStart": 8.684999993420206,
"connectEnd": 8.684999993420206,
"secureConnectionStart": 8.684999993420206,
"requestStart": 15.749999991385266,
"responseStart": 10650.364999994054,
"responseEnd": 13565.22999999288,
"transferSize": 56666,
"encodedBodySize": 56127,
"decodedBodySize": 207120,
"serverTiming": [],
"workerTiming": [],
"unloadEventStart": 10659.469999998691,
"unloadEventEnd": 10659.5299999899,
"domInteractive": 13574.969999986934,
"domContentLoadedEventStart": 13612.624999994296,
"domContentLoadedEventEnd": 13612.629999988712,
"domComplete": 13635.66999998875,
"loadEventStart": 13635.704999993322,
"loadEventEnd": 13636.144999996759,
"type": "navigate",
"redirectCount": 0
}
- A lot of properties have been added to get more detailed information (resource is the same).
// Service worker 响应时间
let workerTime = 0;
if (pageNav.workerStart > 0) {
workerTime = pageNav.responseEnd - pageNav.workerStart;
}
// HTTP header 大小
const headerSize = pageNav.transferSize - pageNav.encodedBodySize;
// 压缩比率,如果是 1 的话,也能说明未开启例如 gzip
const compressionRatio = pageNav.decodedBodySize / pageNav.encodedBodySize;
- Compatible, because if it cannot
performance.getEntriesByType('navigation')
be fetched , no error will be reported but an empty array will be returned.
if (performance.getEntriesByType('navigation').length > 0) {
// We have Navigation Timing API
}
Paint timing
Paint Timing defines two new metrics:
- First-paint (FP, first-paint), the point at which the browser renders any content that is visually different from the content on the screen before navigating. Isn't this time-consuming white screen.
- The first content painting (FCP, first-contentful-paint), the time point when the browser renders the first content from the DOM. Isn't this time-consuming gray screen?
// 直接在代码里这么用的话,不一定取得到,需要轮询
performance.getEntriesByType('paint');
[
{
"name": "first-paint",
"entryType": "paint",
"startTime": 17718.514999956824,
"duration": 0
},
{
"name": "first-contentful-paint",
"entryType": "paint",
"startTime": 17718.519999994896,
"duration": 0
}
]
performance.getEntriesByType
What is returned is an array, and only prepared data can be included in the group. You may need to poll or find an appropriate time point to report the data.
The new standard providesPerformanceObserver
an API to help you monitor whether the response resource data is ready.
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// `name` will be either 'first-paint' or 'first-contentful-paint'.
const metricName = entry.name;
const time = Math.round(entry.startTime + entry.duration);
collect({
name: metricName,
time: time,
});
}
});
observer.observe({
entryTypes: ['paint'/* , 'navigation', resource */]});
- Use needs to be code compatible
if ('performance' in window) {
if ('PerformanceObserver' in window) {
// todo
} else {
// todo
}
}
- Effectively draw First Meaning Paint (FMP) for the first time: Indicates the time point at which the element that the current page most wants to display to the user is rendered, that is, the main element rendering point.
- FMP does not have a standardized definition and needs to develop its own definition. For example, the point in time when the element's growth rate is the steepest.
User timing
performance.mark
Dot, the parameter is the mark of the point name
performance.mark('starting_calculations');
const multiply = 82 * 21;
performance.mark('ending_calculations');
performance.mark('starting_awesome_script');
function awesomeScript() {
console.log('doing awesome stuff');
}
performance.mark('ending_awesome_script');
performance.measure
Calculation, the parameters are point name identification, mark point 1, mark point 2
performance.mark('starting_calculations');
const multiply = 82 * 21;
performance.mark('ending_calculations');
+ performance.measure('multiply_measure', 'starting_calculations', 'starting_calculations');
performance.mark('starting_awesome_script');
function awesomeScript() {
console.log('doing awesome stuff');
}
performance.mark('starting_awesome_script');
+ performance.measure('awesome_script', 'starting_awesome_script', 'starting_awesome_script');
- take out time
const measures = performance.getEntriesByType('measure');
measures.forEach(measureItem => {
console.log(`${
measureItem.name}: ${
measureItem.duration}`);
});
Report data
- Generally, it can be considered to report when the user is about to uninstall the page. There is no doubt that this time point will not interfere with the user's operation on the current page.
However, if the reporting takes a long time, it will affect the user experience of jumping to the next page. can be usednavigator.sendBeacon
.
window.addEventListener('unload', function() {
// 注意 performance.getEntries 会取当前页所有资源包括页面本身的性能信息
// 注意 数据体量问题
let rumData = new FormData();
rumData.append('entries', JSON.stringify(performance.getEntries()));
// 是否支持
if('sendBeacon' in navigator) {
// Beacon 发起请求
if(navigator.sendBeacon(endpoint, rumData)) {
// sendBeacon 发送成功
} else {
// sendBeacon 发送失败! 使用 XHR or fetch 代替
}
} else {
// sendBeacon 不支持! 使用 XHR or fetch 代替
}
}, false);
- Traditional solution, handled
unload
in
- Because the page is unloaded, it will not care about the completion of receiving asynchronous ajax, so synchronous ajax is generally used to block page unloading.
- Create an image and send the request with img src.
- setTimeout(ajax, 0)。
- navigator.sendBeacon solves the above problems
- After the page is uninstalled, asynchronous requests can still be made.
- Does not block unloading of the current page.
- Simple to use.
Summarize
Navigation Timing
Collect HTML document performance metrics.
performance.timing
Commonly used to solve compatibilityperformance.getEntriesByType('navigation')[0]
New standard, high precision, more detailed content, poor compatibility
Resource Timing
Collect performance indicators of resources that HTML depends on, such as CSS, JS, images, fonts, etc.
performance.getEntriesByType('resource')
Use old and new, extended by new standards.
User timing
Collect user-defined
performance.getEntriesByType('measure')
It can be considered to be used to manage FMP.
reference
- HTML DOM standard
- W3C Navigation Timing
- Navigation Timing Level 2
- User Timing Level 2
- boomerang
- commercial boomerang
- Resource Timing practical tips
- Front-end monitoring practice - FMP's intelligent acquisition algorithm
- Assessing Loading Performance in Real Life with Navigation and Resource Timing
- Navigator.sendBeacon
- performance-bookmarklet
- waterfall.js