使用 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 发布文章使用:只允许注册用户才可以访问!


使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包的更多相关文章

  1. 使用 js 实现一个简易版的 GIPHY 动图搜索 web 应用程序

    使用 js 实现一个简易版的 GIPHY 动图搜索 web 应用程序 具有挑战性的前端面试题 API JAMstack refs https://www.infoq.cn/article/0NUjpx ...

  2. 使用 js 实现一个简易版的模版引擎

    使用 js 实现一个简易版的模版引擎 regex (function test() { this.str = str; })( window.Test = ...; format() { let ar ...

  3. 使用 js 实现一个简易版的 drag & drop 库

    使用 js 实现一个简易版的 drag & drop 库 具有挑战性的前端面试题 H5 DnD js refs https://www.infoq.cn/article/0NUjpxGrqRX ...

  4. 使用 js 实现一个简易版的动画库

    使用 js 实现一个简易版的动画库 具有挑战性的前端面试题 animation css refs https://www.infoq.cn/article/0NUjpxGrqRX6Ss01BLLE x ...

  5. 使用 js 实现一个简易版的 async 库

    使用 js 实现一个简易版的 async 库 具有挑战性的前端面试题 series & parallel 串行,并行 refs https://www.infoq.cn/article/0NU ...

  6. 使用 js 实现一个简易版的 vue 框架

    使用 js 实现一个简易版的 vue 框架 具有挑战性的前端面试题 refs https://www.infoq.cn/article/0NUjpxGrqRX6Ss01BLLE xgqfrms 201 ...

  7. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  8. DI 原理解析 并实现一个简易版 DI 容器

    本文基于自身理解进行输出,目的在于交流学习,如有不对,还望各位看官指出. DI DI-Dependency Injection,即"依赖注入":对象之间依赖关系由容器在运行期决定, ...

  9. 依赖注入[5]: 创建一个简易版的DI框架[下篇]

    为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...

随机推荐

  1. jemeter断言和性能分析

    一.添加断言 1.原因:检查是否有该结果,一般一个请求过去除了400和500的只要通过的都会代表请求成功,比如登录页面及时填写了错误密码,虽然会返回密码错误,但这个请求还是成功的,所以我们要添加断言, ...

  2. EF Code First 无法加载指定的元数据资源

    是由属于一般出现这个错误是由于App.config里面配置错误,DB First 是不一样的. 配置文件不止一个地方··多查查其他项目有没有.

  3. Python中,单引号,双引号,三引号的使用区别与原因

    先说1双引号与3个双引号的区别,双引号所表示的字符串通常要写成一行如:s1 = "hello,world"如果要写成多行,那么就要使用/ ("连行符")吧,如s ...

  4. noip 注意事项 (个人向)

    目录 非常重要 对拍 空间 极限数据 模数,YES/NO等大小写 个人 考场 神仙 czdzx 说要写,我也来写 非常重要 对拍 空间 极限数据 模数,YES/NO等大小写 个人 养身体,不要紧张,不 ...

  5. 快速计算C(n,r)

    在网上见的,引用出处为:http://blog.csdn.net/alexingcool/article/details/7997599 可以在logn内计算出,但是容易溢出. [cpp] view ...

  6. ajax带checkbox选择值到后台

    function togglefun(checkbox){//全选 $('input[name=cids]').prop('checked', $(checkbox).prop('checked')) ...

  7. docker第一日学习总结

    查看当前所有的镜像 docker images 查看当前运行的容器 docker ps 一般容器分为后台驻留和闪退(ubuntu\busybox等)两种,对于后台驻留的,我们如果想进入这个容器(前提是 ...

  8. Maven三种打包方式jar war pom

    1.pom工程 用在父级工程或聚合工程中.用来做jar包的版本控制.必须指明这个聚合工程的打包方式为pom 2.war工程 将会打包成war,发布在服务器上的工程.如网站或服务.在SpringBoot ...

  9. 说说 JavaScript中 call和apply

    下面有关JavaScript中 call和apply的描述,错误的是? call与apply都属于Function.prototype的一个方法,所以每个function实例都有call.apply属 ...

  10. 【洛谷 p3379】模板-最近公共祖先(图论--倍增算法求LCA)

    题目:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 解法:倍增. 1 #include<cstdio> 2 #include<cstdlib> 3 #include ...