使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包
使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包
前端监控,埋点,数据收集,性能监控
Beacon API

优点,请求发送是非阻塞的 post ,用户体验好;支持多种数据格式;
缺点,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
W3C Editor's Draft 30 January 2020
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 发布文章使用:只允许注册用户才可以访问!
使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包的更多相关文章
- 使用 js 实现一个简易版的 GIPHY 动图搜索 web 应用程序
使用 js 实现一个简易版的 GIPHY 动图搜索 web 应用程序 具有挑战性的前端面试题 API JAMstack refs https://www.infoq.cn/article/0NUjpx ...
- 使用 js 实现一个简易版的模版引擎
使用 js 实现一个简易版的模版引擎 regex (function test() { this.str = str; })( window.Test = ...; format() { let ar ...
- 使用 js 实现一个简易版的 drag & drop 库
使用 js 实现一个简易版的 drag & drop 库 具有挑战性的前端面试题 H5 DnD js refs https://www.infoq.cn/article/0NUjpxGrqRX ...
- 使用 js 实现一个简易版的动画库
使用 js 实现一个简易版的动画库 具有挑战性的前端面试题 animation css refs https://www.infoq.cn/article/0NUjpxGrqRX6Ss01BLLE x ...
- 使用 js 实现一个简易版的 async 库
使用 js 实现一个简易版的 async 库 具有挑战性的前端面试题 series & parallel 串行,并行 refs https://www.infoq.cn/article/0NU ...
- 使用 js 实现一个简易版的 vue 框架
使用 js 实现一个简易版的 vue 框架 具有挑战性的前端面试题 refs https://www.infoq.cn/article/0NUjpxGrqRX6Ss01BLLE xgqfrms 201 ...
- .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”
FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...
- DI 原理解析 并实现一个简易版 DI 容器
本文基于自身理解进行输出,目的在于交流学习,如有不对,还望各位看官指出. DI DI-Dependency Injection,即"依赖注入":对象之间依赖关系由容器在运行期决定, ...
- 依赖注入[5]: 创建一个简易版的DI框架[下篇]
为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...
随机推荐
- 转 Fiddler4 手机抓包
Fiddler4 手机抓包 文章转自:https://www.cnblogs.com/zhengna/p/10876954.html 1.要对计算机Fiddler进行配置,允许远程计算机连接. 2. ...
- 网络编程-I/O复用
I/O模型 Unix下可用的I/O模型有五种: 阻塞式I/O 非阻塞式I/O I/O复用(select和poll.epoll) 信号驱动式I/O(SIGIO) 异步I/O(POSIX的aio_系列函数 ...
- Redis布隆过滤器与布谷鸟过滤器
大家都知道,在计算机中,IO一直是一个瓶颈,很多框架以及技术甚至硬件都是为了降低IO操作而生,今天聊一聊过滤器,先说一个场景: 我们业务后端涉及数据库,当请求消息查询某些信息时,可能先检查缓存中是否有 ...
- https://design-patterns.readthedocs.io/zh_CN/latest/index.html
图说设计模式 - Graphic Design Patterns https://design-patterns.readthedocs.io/zh_CN/latest/index.html
- __init__ raises an exception, then __del__ will still be called
issue 808164: socket.close() doesn't play well with __del__ - Python tracker https://bugs.python.org ...
- 20201115gryz模拟赛解题报告
写在前面 T1:期望100pts,实际0pts(7:50 ~ 8:50 T2:期望0pts,实际0pts(10:00 ~ 10:35 T3:期望20pts,实际40pts( 9:10 ~ 10:00, ...
- LIS的优化
二分优化 在求一个最长不上升自序列中,显然其结尾元素越小,越有利于接其他元素,对答案的贡献也就可能会更高 那么我们可以用low[i]去存长度为i的LIS结尾元素的最小值 因此我们只要维护low数组 对 ...
- 在nodejs中创建cluster
目录 简介 cluster集群 cluster详解 cluster中的event cluster中的方法 cluster中的属性 cluster中的worker 总结 在nodejs中创建cluste ...
- 写给小白的 Nginx 文章
原文地址:Nginx concepts I wish I knew years ago 原文作者:Aemie Jariwala(已授权) 译者 & 校正:HelloGitHub-小鱼干 &am ...
- MySql(二)索引的设计与使用
MySql(二)索引的设计与使用 一.索引概述 二.设计索引的原则 三.BTREE索引与HASH索引 一.索引概述 所有Mysql列类型都可以被索引,对相关列使用索引时提高select操作性能的最佳途 ...