使用 js 和 Beacon API 實現一個簡易版的前端埋點監控 npm 包


使用 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\n';
});

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

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



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 發布文章使用:只允許注冊用戶才可以訪問!

原創文章,版權所有©️xgqfrms, 禁止轉載 🈲️,侵權必究⚠️!



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM