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

使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包

前端监控,埋点,数据收集,性能监控

Beacon API

https://caniuse.com/beacon

  1. 优点,请求发送是非阻塞的 post ,用户体验好;支持多种数据格式;

  2. 缺点,IE 不支持,使用 XHR 作为 fallback 方案

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2020-01-01
 * @modified
 *
 * @description
 * @difficulty Easy Medium Hard
 * @complexity O(n)
 * @augments
 * @example
 * @link
 * @solutions
 *
 * @best_solutions
 *
 */

const log = console.log;

let startTime = performance.now();

window.addEventListener(`load`, (e) => {
  log(`window load`);
  log(`page is fully loaded`);
});

window.addEventListener(`DOMContentLoaded`, (e) => {
  log(`window DOMContentLoaded`);
  // log(`DOM fully loaded and parsed`);
});

const logVisit = (url = ``) => {
  // Test that we have support
  if (!navigator.sendBeacon) {
    // XHR fallback
    return true;
  } else {
  // URL to send the data to, e.g.
  // let url = `/api/log`;
  // Data to send
  let data = new FormData();
  data.append(`start`, startTime);
  data.append(`end`, performance.now());
  data.append(`url`, document.URL);
  // Let`s go!
  navigator.sendBeacon(url, data);
  }
};

// 将日志记录封装到一个函数中,则可以在页面卸载时调用它。
  // ✅ good place for sendBeacon ???

window.addEventListener(`beforeunload`, (e) => {
  log(`window beforeunload`);
  // ❌ bad place for sendBeacon
  logVisit(`/api/log`);
});

window.addEventListener(`unload`, (e) => {
  log(`window unload`);
  // ❌ bad place for sendBeacon
  // logVisit(`/api/log`);
});


// navigator.sendBeacon(`https://www.xgqfrms.xyz/`, `hello ✅`);


W3C & Beacon

W3C Candidate Recommendation 13 April 2017

https://www.w3.org/TR/beacon/

W3C Editor's Draft 30 January 2020

https://w3c.github.io/beacon/



demos





test

异常关闭浏览器窗口(强制退出 Chrome 进程),验证请求是否会发送成功?

KOA server

React client

WebSocket

load & DOMContentLoaded

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

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

readystate: interactive
DOMContentLoaded
readystate: complete
load

window.addEventListener('load', (event) => {
    log.textContent = log.textContent + 'load
';
});

document.addEventListener('readystatechange', (event) => {
    log.textContent = log.textContent + `readystate: ${document.readyState}
`;
});

document.addEventListener('DOMContentLoaded', (event) => {
    log.textContent = log.textContent + `DOMContentLoaded
`;
});



visibilitychange & pagehide

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

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2020-11-11
 * @modified
 *
 * @description
 * @difficulty Easy Medium Hard
 * @complexity O(n)
 * @augments
 * @example
 * @link
 * @solutions
 *
 * @best_solutions
 *
 */

const log = console.log;

let startTime = performance.now();

window.addEventListener(`load`, (e) => {
  log(`window load`);
  log(`page is fully loaded`);
});

window.addEventListener(`DOMContentLoaded`, (e) => {
  log(`window DOMContentLoaded`);
  // log(`DOM fully loaded and parsed`);
});

const logVisit = (url = ``) => {
  // Test that we have support
  if (!navigator.sendBeacon) {
    // XHR fallback
    return true;
  } else {
  // URL to send the data to, e.g.
  // let url = `/api/log`;
  // Data to send
  let data = new FormData();
  data.append(`start`, startTime);
  data.append(`end`, performance.now());
  data.append(`url`, document.URL);
  // Let`s go!
  navigator.sendBeacon(url, data);
  }
};

// 将日志记录封装到一个函数中,则可以在页面卸载时调用它。
window.addEventListener(`pagehide`, (e) => {
  log(`window beforeunload`);
  // ✅ good place for sendBeacon
  logVisit(`/api/log`);
  if (event.persisted) {
    /* the page isn't being discarded, so it can be reused later */
  }
}, false);



document.addEventListener(`visibilitychange`, (e) => {
// window.addEventListener(`visibilitychange`, (e) => {
  log(`document.visibilityState`, document.visibilityState);
  // if (document.visibilityState === `hidden`) {
  // if (document.visibilityState === `visible`) {
  //   backgroundMusic.play();
  // } else {
  //   backgroundMusic.pause();
  // }
  // log(`window visibilitychange`);
  // ✅ good place for sendBeacon
  logVisit(`/api/log`);
});



window.addEventListener(`beforeunload`, (e) => {
  log(`window beforeunload`);
  // ❌ bad place for sendBeacon
  // logVisit(`/api/log`);
});

window.addEventListener(`unload`, (e) => {
  log(`window unload`);
  // ❌ bad place for sendBeacon
  // logVisit(`/api/log`);
});


// navigator.sendBeacon(`https://www.xgqfrms.xyz/`, `hello ✅`);


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


window.addEventListener("pagehide", event => {
  if (event.persisted) {
    /* the page isn't being discarded, so it can be reused later */
  }
}, false);

beforeunload & unload

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

window.addEventListener('beforeunload', (event) => {
  // Cancel the event as stated by the standard.
  event.preventDefault();
  // Older browsers supported custom message
  event.returnValue = '';
});

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

refs

MDN

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

https://developer.mozilla.org/en-US/docs/Glossary/beacon

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



©xgqfrms 2012-2020

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


原文地址:https://www.cnblogs.com/xgqfrms/p/13954019.html