使用 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框架[上篇]> ...
随机推荐
- 【故障公告】K8s CofigMap 挂载问题引发网站故障
今天凌晨我们用阿里云服务器自建的 kubernetes 集群出现突发异常情况,博客站点(blog-web)与博客 web api(blog-api)的 pod 无法正常启动(CrashLoopBack ...
- SpringCloud zuul 网关限流分析
最近项目中 spring cloud zuul 运用到限流功能,打算配置一下就直接使用,不过在压测与调优过程中遇到一些没有预测到的问题,附上排查与解析结果 yml.pom配置 强烈推荐,按最新gith ...
- 2021/1/20随记,MTU
背景: 事情是这样的,客户2台防火墙部署了ipsec,内网互通,但是其中ssh以及其他大命令之类的操作就会卡住,简单的vi命令可以使用. 解决: 排除网络问题,因为内网互通,其次是系统层面问题,最终定 ...
- 为什么从REST转向gRPC 需要流式传输搜索结果,也就是在有第一批结果时就开始传输
https://mp.weixin.qq.com/s/aEO3Y8SkObNgfQU3z8sH2w 我们为什么从REST转向gRPC 原创 Levin Fritz InfoQ 2019-06-23 作 ...
- 前序遍历 排序 二叉搜索树 递归函数的数学定义 return 递归函数不能定义为内联函数 f(x0)由f(f(x0))决定
遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化 1. 二叉树3个基本单元组成:根节点.左子树.右子树 以L.D.R ...
- Opencart 后台getshell
朋友实战中遇到的,帮忙看后台getshell. 修改日志文件,但是奈何找不到warning这类等级的错误,没办法控制写入的内容,通过sql报错能写入了,但是尖括号却会被实体,使用16进制一样会实体.. ...
- RocketMQ 常用消息类型
文章首发于公众号<程序员果果> 地址 : https://mp.weixin.qq.com/s/dYqGd9zi2mNelsNNLIribg 消息发送示例 导入依赖: <depend ...
- 知道 Redis-Cluster 么?说说其中可能不可用的情况
Redis 集群模式简述 一个集群模式的官方推荐最小最佳实践方案是 6 个节点,3 个 Master 3 个 Slave 的模式,如 图00 所示. key 分槽与转发机制 Redis 将键空间分为了 ...
- Spark-1.6.1 Hadoop-2.6.4 VMware Ubuntu 分布式集群搭建 全过程
本文从头开始零基础完全配置,适合小白. 本文在vmware中配置三台虚拟机,一台做Master,两台Worker,hadoop 和spark只需要在Master上配置,然后cp到worker上,包括配 ...
- java中的IO处理和使用,API详细介绍(二)
字符流 [向文件中写入数据] 现在我们使用字符流 /** * 字符流 * 写入数据 * */ import java.io.*; class hello{ public static void mai ...