使用 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. synchronized的jvm源码分析聊锁的意义

    上篇写完了ReentrantLock源码实现,从我们的角度分析设计锁,在对比大神的实现,顺道拍了一波道哥的马屁,虽然他看不到,哈哈.这一篇我们来聊一聊synchronized的源码实现,并对比reen ...

  2. WIFI 国家码和信道划分

    前言 网上百度了很多资料,都没有找到国家码对应支持哪些信道的资料,无奈只能qiang到谷歌,分享给大家完整的WIFI 国家码和信道划分. 安卓WIFI国家码的影响 android中设置wifi国家码的 ...

  3. Linux更改密码报错:密码未通过字典检查 - 过于简单化/系统化

    Linux更改密码报错:密码未通过字典检查 - 过于简单化/系统化 方案一:直接忽略 很容易认为这儿是一个错误,其实可以直接忽略,重新输入密码 [root@localhost ~]# passwd 更 ...

  4. java创建线程的多种方式

    java创建线程的四种方式 1.继承 Thread 类 通过继承 Thread 类,并重写它的 run 方法,我们就可以创建一个线程. 首先定义一个类来继承 Thread 类,重写 run 方法. 然 ...

  5. JavaScript——事件

    事件:是由访问Web页面的用户引起一系列操作. 事件的作用:用于浏览器和用户的交互 以下代码为相关试验代码: HTML事件: <script type="text/javascript ...

  6. MySql数据表设计,索引优化,SQL优化,其他数据库

    MySql数据表设计,索引优化,SQL优化,其他数据库 1.数据表设计 1.1数据类型 1.2避免空值 1.3text类型优化 2.索引优化 2.1索引分类 2.2索引优化 3.SQL优化 3.1分批 ...

  7. 函数式编程(logging日志管理模块)

    本节内容 日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模块日志流处理流程 使用logging四大组件记录日志 配置logging的几种方式 向日 ...

  8. C++类基本--随笔二

    1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 5 class Internet 6 ...

  9. TZOJ6556: 嗅探器

    最近在练Tarjan,看到这道题目分类在割点里面就想尝试做一下,点开发现题目数据范围竟然如此之小,算了,bfs暴力一发. 题目意思就是你需要找到一个关键节点,也可以理解成,行军打仗时必需经过的地方,敌 ...

  10. 一统江湖的大前端(10)——inversify.js控制反转

    <大史住在大前端>前端技术博文集可在下列地址访问: [github总基地][博客园][华为云社区][掘金] 字节跳动幸福里大前端团队邀请各路高手前来玩耍,团队和谐有爱,技术硬核,字节范儿正 ...