xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

Web Vitals All In One

Web Vitals All In One

Web 指标

  1. Largest Contentful Paint (LCP): measures loading performance.
    To provide a good user experience, LCP should occur within 2.5 seconds of when the page first starts loading.

  2. First Input Delay (FID): measures interactivity.
    To provide a good user experience, pages should have a FID of 100 milliseconds or less.

  3. Cumulative Layout Shift (CLS): measures visual stability.
    To provide a good user experience, pages should maintain a CLS of 0.1. or less.

demo

https://www.npmjs.com/package/web-vitals

import {getCLS, getFID, getLCP} from 'web-vitals';

// onReport callback
function sendToAnalytics(metric) {
  // 收集的性能指标数据
  const body = JSON.stringify(metric);
  if(navigator.sendBeacon) {
    // Use `navigator.sendBeacon()` if available
    navigator.sendBeacon('/analytics', body)
  } else {
    // falling back to `fetch()`.
    fetch('/analytics', {body, method: 'POST', keepalive: true});
    // keepalive ❓
  }
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);



// once call 当指标准备好报告时
getCLS(console.log);

// multi call 报告每次更改的值
getCLS(console.log, true);

import {getCLS, getFID, getLCP} from 'web-vitals';

// 仅报告更改的增量
function logDelta({name, id, delta}) {
  console.log(`${name} matching ID ${id} changed by ${delta}`);
}

getCLS(logDelta);
getFID(logDelta);
getLCP(logDelta);

PerformanceObserver

https://web.dev/vitals/
https://web.dev/i18n/zh/vitals/

https://github.com/GoogleChrome/web-vitals

// 将多个报告一起批处理

import {getCLS, getFID, getLCP} from 'web-vitals';

const queue = new Set();

function addToQueue(metric) {
  queue.add(metric);
}

function flushQueue() {
  if (queue.size > 0) {
    // Replace with whatever serialization method you prefer.
    // Note: JSON.stringify will likely include more data than you need.
    const body = JSON.stringify([...queue]);

  if(navigator.sendBeacon) {
    // Use `navigator.sendBeacon()` if available
    navigator.sendBeacon('/analytics', body)
  } else {
    // falling back to `fetch()`.
    fetch('/analytics', {body, method: 'POST', keepalive: true});
    // keepalive ❓
  }
    // 上报完成,清零
    queue.clear();
  }
}

getCLS(addToQueue);
getFID(addToQueue);
getLCP(addToQueue);

// Report all available metrics whenever the page is backgrounded or unloaded.
// 当页面后台或卸载时报告所有可用指标。
addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    flushQueue();
  }
});

// NOTE: Safari does not reliably fire the `visibilitychange` event when the  page is being unloaded.
// If Safari support is needed, you should also flush the queue in the `pagehide` event.
addEventListener('pagehide', flushQueue);

Note: see the Page Lifecycle guide for an explanation of why visibilitychange and pagehide are recommended over events like beforeunload and unload.

https://developers.google.com/web/updates/2018/07/page-lifecycle-api#legacy-lifecycle-apis-to-avoid

cdn

<!-- Append the `?module` param to load the module version of `web-vitals` -->
<script type="module">
  import {getCLS, getFID, getLCP} from 'https://unpkg.com/web-vitals?module';

  getCLS(console.log);
  getFID(console.log);
  getLCP(console.log);
</script>

<script>
(function() {
  var script = document.createElement('script');
  script.src = 'https://unpkg.com/web-vitals/dist/web-vitals.iife.js';
  script.onload = function() {
    // When loading `web-vitals` using a classic script, all the public
    // methods can be found on the `webVitals` global namespace.
    webVitals.getCLS(console.log);
    webVitals.getFID(console.log);
    webVitals.getLCP(console.log);
  }
  document.head.appendChild(script);
}())
</script>

Metric

interface Metric {
  // The name of the metric (in acronym form).
  name: 'CLS' | 'FCP' | 'FID' | 'LCP' | 'TTFB';

  // The current value of the metric.
  value: number;

  // The delta between the current value and the last-reported value.
  // On the first report, `delta` and `value` will always be the same.
  delta: number;

  // A unique ID representing this particular metric that's specific to the
  // current page. This ID can be used by an analytics tool to dedupe
  // multiple values sent for the same metric, or to group multiple deltas
  // together and calculate a total.
  id: string;

  // Any performance entries used in the metric value calculation.
  // Note, entries will be added to the array as the value changes.
  entries: (PerformanceEntry | FirstInputPolyfillEntry | NavigationTimingPolyfillEntry)[];
}


interface ReportHandler {
  (metric: Metric): void;
}

// Event Timing API
type FirstInputPolyfillEntry = Omit<PerformanceEventTiming, 'processingEnd' | 'toJSON'>

interface FirstInputPolyfillCallback {
  (entry: FirstInputPolyfillEntry): void;
}


// Navigation Timing API Level 2 
export type NavigationTimingPolyfillEntry = Omit<PerformanceNavigationTiming,
  'initiatorType' | 'nextHopProtocol' | 'redirectCount' | 'transferSize' |
  'encodedBodySize' | 'decodedBodySize' | 'toJSON'>

interface WebVitalsGlobal {
  firstInputPolyfill: (onFirstInput: FirstInputPolyfillCallback) => void;
  resetFirstInputPolyfill: () => void;
  firstHiddenTime: number;
}


interface WebVitalsGlobal {
  firstInputPolyfill: (onFirstInput: FirstInputPolyfillCallback) => void;
  resetFirstInputPolyfill: () => void;
  firstHiddenTime: number;
}


type getCLS = (onReport: ReportHandler, reportAllChanges?: boolean) => void

type getFCP = (onReport: ReportHandler, reportAllChanges?: boolean) => void

type getFID = (onReport: ReportHandler, reportAllChanges?: boolean) => void

type getLCP = (onReport: ReportHandler, reportAllChanges?: boolean) => void

type getTTFB = (onReport: ReportHandler, reportAllChanges?: boolean) => void



import {getTTFB} from 'web-vitals';

getTTFB((metric) => {
  // Calculate the request time by subtracting from TTFB
  // everything that happened prior to the request starting.
  const requestTime = metric.value - metric.entries[0].requestStart;
  console.log('Request time:', requestTime);
});


DOM 高分辨率时间戳 / DOM 高精度时间戳

https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp

automation test framework

Next-gen browser and mobile automation test framework for Node.js


$ npm install --save-dev @wdio/cli
$ npx wdio config --yes
$ npx wdio run

https://webdriver.io/

https://github.com/webdriverio/webdriverio

Google Analytics

analytics.js

import {getCLS, getFID, getLCP} from 'web-vitals';

function sendToGoogleAnalytics({name, delta, id}) {
  // Assumes the global `ga()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/analyticsjs
  ga('send', 'event', {
    eventCategory: 'Web Vitals',
    eventAction: name,
    // The `id` value will be unique to the current page load. When sending
    // multiple values from the same page (e.g. for CLS), Google Analytics can
    // compute a total by grouping on this ID (note: requires `eventLabel` to
    // be a dimension in your report).
    eventLabel: id,
    // Google Analytics metrics must be integers, so the value is rounded.
    // For CLS the value is first multiplied by 1000 for greater precision
    // (note: increase the multiplier for greater precision if needed).
    eventValue: Math.round(name === 'CLS' ? delta * 1000 : delta),
    // Use a non-interaction event to avoid affecting bounce rate.
    nonInteraction: true,
    // Use `sendBeacon()` if the browser supports it.
    transport: 'beacon',

    // OPTIONAL: any additional params or debug info here.
    // See: https://web.dev/debug-web-vitals-in-the-field/
    // dimension1: '...',
    // dimension2: '...',
    // ...
  });
}

getCLS(sendToGoogleAnalytics);
getFID(sendToGoogleAnalytics);
getLCP(sendToGoogleAnalytics);

gtag.js (Universal Analytics)

import {getCLS, getFID, getLCP} from 'web-vitals';

function sendToGoogleAnalytics({name, delta, id}) {
  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/gtagjs
  gtag('event', name, {
    event_category: 'Web Vitals',
    // The `id` value will be unique to the current page load. When sending
    // multiple values from the same page (e.g. for CLS), Google Analytics can
    // compute a total by grouping on this ID (note: requires `eventLabel` to
    // be a dimension in your report).
    event_label: id,
    // Google Analytics metrics must be integers, so the value is rounded.
    // For CLS the value is first multiplied by 1000 for greater precision
    // (note: increase the multiplier for greater precision if needed).
    value: Math.round(name === 'CLS' ? delta * 1000 : delta),
    // Use a non-interaction event to avoid affecting bounce rate.
    non_interaction: true,

    // OPTIONAL: any additional params or debug info here.
    // See: https://web.dev/debug-web-vitals-in-the-field/
    // metric_rating: 'good' | 'ni' | 'poor',
    // debug_info: '...',
    // ...
  });
}

getCLS(sendToGoogleAnalytics);
getFID(sendToGoogleAnalytics);
getLCP(sendToGoogleAnalytics);

https://developers.google.com/analytics/devguides/reporting/core/v4

https://developers.google.com/analytics/devguides/reporting/core/v4/quickstart/web-js

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello Analytics Reporting API V4</title>
  <meta name="google-signin-client_id" content="<REPLACE_WITH_CLIENT_ID>">
  <meta name="google-signin-scope" content="https://www.googleapis.com/auth/analytics.readonly">
</head>
<body>

<h1>Hello Analytics Reporting API V4</h1>

<!-- The Sign-in button. This will run `queryReports()` on success. -->
<p class="g-signin2" data-onsuccess="queryReports"></p>

<!-- The API response will be printed here. -->
<textarea cols="80" rows="20" id="query-output"></textarea>

<script>
  // Replace with your view ID.
  var VIEW_ID = '<REPLACE_WITH_VIEW_ID>';

  // Query the API and print the results to the page.
  function queryReports() {
    gapi.client.request({
      path: '/v4/reports:batchGet',
      root: 'https://analyticsreporting.googleapis.com/',
      method: 'POST',
      body: {
        reportRequests: [
          {
            viewId: VIEW_ID,
            dateRanges: [
              {
                startDate: '7daysAgo',
                endDate: 'today'
              }
            ],
            metrics: [
              {
                expression: 'ga:sessions'
              }
            ]
          }
        ]
      }
    }).then(displayResults, console.error.bind(console));
  }

  function displayResults(response) {
    var formattedJson = JSON.stringify(response.result, null, 2);
    document.getElementById('query-output').value = formattedJson;
  }
</script>

<!-- Load the JavaScript API client and Sign-in library. -->
<script src="https://apis.google.com/js/client:platform.js"></script>

</body>
</html>

Google Analytics Reporting API

https://github.com/GoogleChromeLabs/web-vitals-report

https://developers.google.com/analytics/devguides/reporting

refs

Web 性能监控

https://github.com/web-fullstack/web-vitals

https://www.cnblogs.com/xgqfrms/p/16514500.html



©xgqfrms 2012-2020

www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!


posted @ 2022-07-24 16:42  xgqfrms  阅读(52)  评论(2编辑  收藏  举报