If we want to improve our front-end performance, you have to know how to measure your front-end performance first. But what front-end performance metrics should we focus on? In the Web1.0 era, when we talked about front-end performance metrics, the most common thing we used was page load time. In the era of more and more single-page applications, a single page Load time indicator cannot fully measure front-end performance, because a single-page application page Load time may only trigger once, but the user will have many interactions with the application, and each interaction or action needs to have indicators to measure its performance.

Here are some important front-end performance metrics:

  • First Paint (FP): This metric marks the time when the browser renders the first pixel
  • First Contentful Paint (FCP): Unlike FP, which marks the time when any pixel is rendered,FCP marks the time when the browser renders the first content element, which can be text,image,SVG, or Canvas.

Both of these metrics are important to the user, and they can be interpreted as our application telling the user that we are doing the right thing.

  • First Meaningful Paint (FMP): This metric marks the rendering of the most important area of the First screen, which is usually the area that users are most concerned about. For example, the video playing area of a video site, the first search result area of a search site, or the photo header of a shopping site. It is often difficult for the browser to know which areas are most critical for the first screen, so it is important for the developer to tell the browser which areas are critical.

This is also a key metric, often if the user can quickly see that the most important area has been rendered, the user may not notice even if the rest of the area has not been rendered.

  • Long Task: We all know that browsers are single-threaded in response to user actions by adding tasks to the task queue and executing them one by one. This means that if we have a long task that takes a long time, the rest of the tasks in the queue will have to wait, responding to the user’s actions will be slow, or the animation will stall.
  • Time to Interactive (TTI): This indicator indicates that the browser has rendered the content we need to display on the first screen and is ready to accept user interaction. It also indicates whether the application is available. The program is temporarily unable to respond to user interactions for several reasons:
    • The javascript that needs to be executed has not yet been executed.
    • There are long missions blocking the main thread. Unable to give user response.
indicators introduce
first paint (FP)/first contentful paint (FCP) Does the program start rendering correctly
First meaningful paint (FMP) The first screen content display that users are most concerned about
Time to interactive (TTI) Whether the program is available
long task The experience of using the program (response latency, animation stutter)

There are other indicators such as First Input Delay, First CPU Idle: these indicators are directly related to the above indicators.

The user experience

Knowing these indicators, what time should we control these indicators to bring better user experience to the user? There is such a table below

time introduce
0 to 16 ms The user wants to see the animation can be smooth, animation caton can lead to a very poor user experience, on the browser rendering 60 frames per second of animation can maintain smooth, this is about 16 ms render a frame, the 16 ms including the browser to render the new element to the time required for the page, that is to say, program has about 10 ms can operate.
0 to 100 ms By responding to the user’s interaction within this time, the user will feel that the response is very timely
From 100 to 300 ms The user will feel some lag
From 300 to 1000 ms This is a normal load jump time when some page load or page jump is performed
1000 ms or above After 1000ms(1 second), the user gradually loses patience and attention for the previous operation
10000 ms or above When you respond for more than 10 seconds, the user will get annoyed and stop before the operation

The latency above depends on what network and device you are using, such as the computer and wifi network you are using. Users at 1000ms is a realistic target. But loading in 5000ms is a more realistic goal when your device is a mobile network with only 3G.

Response time: the operation of responding users is within 50ms

Most of the time, when you’re using an application, most of the time the user is waiting for the site to respond to their actions like clicking a button, typing something in a text box, rather than waiting for the site to load. The ideal response time for a website is less than 100ms.

100ms? Isn’t it 50ms?

Our goal is to respond to user actions in less than 100ms, so why is the response time for processing users only 50ms? As we receive input from the user, other tasks may be performing. For example, if A user enters an A in the text box and the browser is performing other tasks, the browser will queue this operation and wait for the browser to complete the previous task before processing the user’s response. So conservatively, in order for the user to get the response within 100ms, our execution time for processing the user response is 50ms.

Animation: It takes about 10ms to produce each frame of animation

In theory the animation should look smooth as long as no more than 16ms of frames are rendered, but the browser takes about 6ms to render each frame onto the screen. So each frame of animation takes about 10ms to generate for the program.

The more idle time the main thread has, the better

The main thread should have as much idle time as possible so that it can respond immediately to user interactions when they occur. When the main thread is idle, the browser has a lot of internal procedures to execute, such as idle GC, etc.

The main content is rendered and the program can interact within 5 seconds

When pages load slowly, users lose patience. The loading and response speed of a website directly affects the user experience.

How are these metrics tested

Use testing tools or websites

  • Chrome DevTools-Audits
  • WebPageTest
  • SpeedCurve

Get these metrics in a real user environment

Let’s talk about some apis before we talk about how to do this in a real user environment or these metrics. Okay

  • Performance. Mark: Creates a timestamp of the given tag.
  • Performance. Measure: The elapsed time between two Marks
  • PerformanceObserver: PerformanceObserver interface used to monitor performance, can according to the incoming object returns the corresponding PerformanceEntry monitoring events.
Get FP/FCP
const observer = new PerformanceObserver((list) = > {
    for (const entry of list.getEntries()) {
      // Name is used to distinguish between 'first-paint' and 'first-contentful-paint'
      const metricName = entry.name;
      const time = Math.round(entry.startTime + entry.duration);
      reportToServer({
        eventCategory: 'Performance Metrics'.eventAction: metricName,
        eventValue: time,
        nonInteraction: true}); }}); observer.observe({entryTypes: ['paint']});
Copy the code
Get FMP based on the most important elements of your first screen

As mentioned earlier, it is very easy for browsers to know exactly how much time each site displays for an important area, so only developers can accurately find the most important area to obtain FMP, assuming that the most important element of our site’s first screen is an image.

<img src="important.jpg" onload="performance.clearMarks('img displayed'); performance.mark('img displayed');">
<script>
performance.clearMarks("img displayed");
performance.mark("img displayed");
</script>
Copy the code
For TTI

There is currently no way to get the TTI interface in PerformanceObserver, which is known through this TLI-Polyfill

import ttiPolyfill from 'tti-polyfill.js';

ttiPolyfill.getFirstConsistentlyInteractive().then((tti) = > {
  reportToServer({
    eventCategory: 'Performance Metrics'.eventAction: 'TTI'.eventValue: tti,
    nonInteraction: true}); });Copy the code
Long watch mission

As mentioned earlier, long tasks can affect the browser’s responsiveness to the user or cause animation to lag. Then it is necessary to be aware of long tasks and shorten them. (The long task API considers tasks over 50ms as long tasks)

const observer = new PerformanceObserver((list) = > {
  for (const entry of list.getEntries()) {
    reportToServer({
      eventCategory: 'Performance Metrics'.eventAction: 'longtask'.eventValue: Math.round(entry.startTime + entry.duration),
      // The long task here contains an attribute
      //https://w3c.github.io/longtasks/#sec-TaskAttributionTiming
      eventLabel: JSON.stringify(entry.attribution), }); }}); observer.observe({entryTypes: ['longtask']});
Copy the code
Monitoring response latency

Long tasks can block the thread and render the browser unable to respond to user actions. As mentioned earlier, if you can respond to user actions within 100ms, it is not too late for users to feel stuck, so it is important to be able to monitor the response time of your key interactions

const submitBtn = document.querySelector('#submit');

submitBtn.addEventListener('click', (event) => {
  const lag = performance.now() - event.timeStamp;
  if (lag > 100) {
    reportToServer({
      eventCategory: 'Performance Metric'
      eventAction: 'input-latency'.eventLabel: '#subscribe:click'.eventValue: Math.round(lag),
      nonInteraction: true}); }});Copy the code
Survivor bias

If the loading speed of our program is very slow (for example, too many JS are loaded), then real users may have quit the site before the loading is completed under the circumstance of inconsistent network environment, and there will be a problem of survivor bias. The users you monitor are already loaded. To be able to detect exiting users at the same time.

/// write at the top
window.__trackAbandons = (a)= > {
  // Remove event listening so this method is executed only once
  document.removeEventListener('visibilitychange'.window.__trackAbandons);
  // Since we haven't loaded the Report JS API yet, we need to ask the server to provide a POST interface to receive the request
  const ANALYTICS_URL = 'https://ANALYTICS_URL';
  const TRACKING_ID = 'TRACKING_ID';
  const CLIENT_ID = (Math.random() * Math.pow(2.52));

  // Send the data to Google Analytics via the Measurement Protocol.
  navigator.sendBeacon && navigator.sendBeacon(ANALYTICS_URL, [
    'v=1'.'t=event'.'ec=Load'.'ea=abandon'.'ni=1'.'dl=' + encodeURIComponent(location.href),
    'dt=' + encodeURIComponent(document.title),
    'tid=' + TRACKING_ID,
    'cid=' + CLIENT_ID,
    'ev=' + Math.round(performance.now()),
  ].join('&'));
};
Visibilitychange can listen for page Unload events
//https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event
document.addEventListener('visibilitychange'.window.__trackAbandons);
Copy the code

conclusion

Performance is becoming more and more important in today’s programs, so when a program needs to be optimized for performance. In my opinion, it can be carried out in this order:

Data collection -> discuss performance indicator thresholds -> Optimize for performance -> re-validate optimization results with data

Here we focus on some of our performance metrics and the way we collected them, and how to optimize for each one will be discussed later.