范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

腾讯二面现在要你实现一个埋点监控SDK,你会怎么设计?

  大家好,我是年年!
  这是小伙伴上周被问到的一个综合性设计题,如果是没有用过埋点监控系统,或者没有深入了解,基本就凉凉。
  这篇文章会讲清楚: 埋点监控系统负责处理哪些问题,需要怎么设计api? 为什么用img的src做请求的发送,sendBeacon又是什么? 在react、vue的错误边界中要怎么处理? 什么是埋点监控SDK
  举个例子,公司开发上线了一个网站,但开发人员不可能预测,用户实际使用时会发生什么:用户浏览过哪几个页面?几成用户会点击某个弹窗的确认按钮,几成会点击取消?有没有出现页面崩溃?
  所以我们需要一个埋点监控SDK去做数据的收集,后续再统计分析。有了分析数据,才能有针对性对网站进行优化:PV特别少的页面就不要浪费大量人力;有bug的页面赶紧修复,不然要325了。
  比较有名的埋点监控有Google Analytics,除了web端,还有iOS、安卓的SDK。
  公众号后台回复「ReactSDK」可获取react版本的github  埋点监控的职能范围
  因为业务需要的不同,大部分公司都会自己开发一套埋点监控系统,但基本上都会涵盖这三类功能:用户行为监控
  负责统计PV(页面访问次数)、UV(页面访问人数)以及用户的点击操作等行为。
  这类统计是用的最多的,有了这些数据才能量化我们的工作成果。页面性能监控
  开发和测试人员固然在上线之前会对这些数据做评估,但用户的环境和我们不一样,也许是3G网,也许是很老的机型,我们需要知道在实际使用场景中的性能数据,比如页面加载时间、白屏时间等。错误报警监控
  获取错误数据,及时处理才能避免大量用户受到影响。除了全局捕获到的错误信息,还有在代码内部被catch住的错误告警,这些都需要被收集到。
  下面会从api的设计出发,对上述三种类型进一步展开。SDK的设计
  在开始设计之前,先看一下SDK怎么使用import StatisticSDK from "StatisticSDK"; // 全局初始化一次 window.insSDK = new StatisticSDK("uuid-12345");    复制代码
  首先把SDK实例挂载到全局,之后在业务代码中调用,这里的新建实例时需要传入一个id,因为这个埋点监控系统往往是给多个业务去使用的,通过id去区分不同的数据来源。
  首先实现实例化部分:class StatisticSDK {   constructor(productID){     this.productID = productID;   } } 复制代码数据发送
  数据发送是一个最基础的api,后面的功能都要基于此进行。通常这种前后端分离的场景会使用AJAX的方式发送数据,但是这里使用图片的src属性。原因有两点:没有跨域的限制,像srcipt标签、img标签都可以直接发送跨域的GET请求,不用做特殊处理;兼容性好,一些静态页面可能禁用了脚本,这时script标签就不能使用了;
  但要注意,这个图片不是用来展示的,我们的目的是去「传递数据」,只是借助img标签的的src属性,在其url后面拼接上参数,服务端收到再去解析。class StatisticSDK {   constructor(productID){     this.productID = productID;   }   send(baseURL,query={}){     query.productID = this.productID;     let queryStr = Object.entries(query).map(([key, value]) => `${key}=${value}`).join("&")     let img = new Image();     img.src = `${baseURL}?${queryStr}`   } } 复制代码
  img标签的优点是不需要将其append到文档,只需设置src属性便能成功发起请求。
  通常请求的这个url会是一张1X1px的GIF图片,网上的文章对于这里为什么返回图片的是一张GIF都是含糊带过,这里查阅了一些资料并测试了:同样大小,不同格式的的图片中GIF大小是最小的,所以选择返回一张GIF,这样对性能的损耗更小;如果返回204,会走到img的onerror事件,并抛出一个全局错误;如果返回200和一个空对象会有一个CORB的告警;
  当然如果不在意这个报错可以采取返回空对象,事实上也有一些工具是这样做的  有一些埋点需要真实的加到页面上,比如垃圾邮件的发送者会添加这样一个隐藏标志来验证邮件是否被打开,如果返回204或者是200空对象会导致一个明显图片占位符 复制代码
  更优雅的web beacon
  这种打点标记的方式被称web beacon(网络信标)。除了gif图片,从2014年开始,浏览器逐渐实现专门的API,来更优雅的完成这件事:Navigator.sendBeacon
  使用很简单Navigator.sendBeacon(url,data) 复制代码
  相较于图片的src,这种方式的更有优势:不会和主要业务代码抢占资源,而是在浏览器空闲时去做发送;并且在页面卸载时也能保证请求成功发送,不阻塞页面刷新和跳转;
  现在的埋点监控工具通常会优先使用sendBeacon,但由于浏览器兼容性,还是需要用图片的src兜底。用户行为监控
  上面实现了数据发送的api,现在可以基于它去实现用户行为监控的api。class StatisticSDK {   constructor(productID){     this.productID = productID;   }   // 数据发送   send(baseURL,query={}){     query.productID = this.productID;       let queryStr = Object.entries(query).map(([key, value]) => `${key}=${value}`).join("&")       let img = new Image();       img.src = `${baseURL}?${queryStr}`   }   // 自定义事件   event(key, val={}) {     let eventURL = "http://demo/"     this.send(eventURL,{event:key,...val})   }   // pv曝光   pv() {     this.event("pv")   } } 复制代码
  用户行为包括自定义事件和pv曝光,也可以把pv曝光看作是一种特殊的自定义行为事件。页面性能监控
  页面的性能数据可以通过performance.timing这个API获取到,获取的数据是单位为毫秒的时间戳。
  上面的不需要全部了解,但比较关键的数据有下面几个,根据它们可以计算出FP/DCL/Load等关键事件的时间点:页面首次渲染时间:FP(firstPaint)=domLoading-navigationStart  DOM加载完成:DCL(DOMContentEventLoad)=domContentLoadedEventEnd-navigationStart  图片、样式等外链资源加载完成:L(Load)=loadEventEnd-navigationStart
  上面的数值可以跟performance面板里的结果对应。
  回到SDK,我们只用实现一个上传所有性能数据的api就可以了:class StatisticSDK {   constructor(productID){     this.productID = productID;     // 初始化自动调用性能上报     this.initPerformance()   }   // 数据发送   send(baseURL,query={}){     query.productID = this.productID;       let queryStr = Object.entries(query).map(([key, value]) => `${key}=${value}`).join("&")       let img = new Image();       img.src = `${baseURL}?${queryStr}`   }   // 性能上报   initPerformance(){     let performanceURL = "http://performance/"     this.send(performanceURL,performance.timing)   } } 复制代码
  并且,在构造函数里自动调用,因为性能数据是必须要上传的,就不需要用户每次都手动调用了。错误告警监控
  错误报警监控分为JS原生错误和React/Vue的组件错误的处理。JS原生错误
  除了try catch中捕获住的错误,我们还需要上报没有被捕获住的错误——通过error事件和unhandledrejection事件去监听。error
  error事件是用来监听DOM操作错误DOMException  和JS错误告警的,具体来说,JS错误分为下面8类:InternalError: 内部错误,比如如递归爆栈;RangeError: 范围错误,比如new Array(-1);EvalError: 使用eval()时错误;ReferenceError: 引用错误,比如使用未定义变量;SyntaxError: 语法错误,比如var a = ;TypeError: 类型错误,比如[1,2].split(".");URIError: 给 encodeURI或 decodeURl()传递的参数无效,比如decodeURI("%2")Error: 上面7种错误的基类,通常是开发者抛出
  也就是说,代码运行时发生的上述8类错误,都可以被检测到。unhandledrejection
  Promise内部抛出的错误是无法被error捕获到的,这时需要用unhandledrejection事件。
  回到SDK的实现,处理错误报警的代码如下:class StatisticSDK {   constructor(productID){     this.productID = productID;     // 初始化错误监控     this.initError()   }   // 数据发送   send(baseURL,query={}){     query.productID = this.productID;       let queryStr = Object.entries(query).map(([key, value]) => `${key}=${value}`).join("&")       let img = new Image();       img.src = `${baseURL}?${queryStr}`   }   // 自定义错误上报   error(err, etraInfo={}) {     const errorURL = "http://error/"     const { message, stack } = err;     this.send(errorURL, { message, stack, ...etraInfo})   }   // 初始化错误监控   initError(){     window.addEventListener("error", event=>{       this.error(error);     })     window.addEventListener("unhandledrejection", event=>{       this.error(new Error(event.reason), { type: "unhandledrejection"})     })   } } 复制代码
  和初始化性能监控一样,初始化错误监控也是一定要做的,所以需要在构造函数中调用。后续开发人员只用在业务代码的try catch中调用error方法即可。React/Vue组件错误
  成熟的框架库都会有错误处理机制,React和Vue也不例外。React的错误边界
  错误边界是希望当应用内部发生渲染错误时,不会整个页面崩溃。我们提前给它设置一个兜底组件,并且可以细化粒度,只有发生错误的部分被替换成这个「兜底组件」,不至于整个页面都不能正常工作。
  它的使用很简单,就是一个带有特殊生命周期的类组件,用它把业务组件包裹起来。
  这两个生命周期是getDerivedStateFromError  和componentDidCatch  ,
  代码如下:// 定义错误边界 class ErrorBoundary extends React.Component {   state = { error: null }   static getDerivedStateFromError(error) {     return { error }   }   componentDidCatch(error, errorInfo) {     // 调用我们实现的SDK实例     insSDK.error(error, errorInfo)   }   render() {     if (this.state.error) {       return 

Something went wrong.

} return this.props.children } } ... 复制代码   建了一个在线sandbox可以体验,公众号后台回复「错误边界demo」获取地址   回到SDK的整合上,在生产环境下,被错误边界包裹的组件,如果内部抛出错误,全局的error事件是无法监听到的,因为这个错误边界本身就相当于一个try catch。所以需要在错误边界这个组件内部去做上报处理。也就是上面代码中的componentDidCatch 生命周期。Vue的错误边界   vue也有一个类似的生命周期来做这件事,不再赘述:errorCaptured Vue.component("ErrorBoundary", { data: () => ({ error: null }), errorCaptured (err, vm, info) { this.error = `${err.stack} found in ${info} of component` // 调用我们的SDK,上报错误信息 insSDK.error(err,info) return false }, render (h) { if (this.error) { return h("pre", { style: { color: "red" }}, this.error) } return this.$slots.default[0] } }) ... 复制代码   现在我们已经实现了一个完整的SDK的骨架,并且处理了在实际开发时,react/vue项目应该怎么接入。   实际生产使用的SDK会更健壮,但思路也不外乎,感兴趣的可以去读一读源码。结语   文章比较长,但想答好这个问题,这些知识储备都是必须的。   我们要设计SDK,首先要清楚它的基本使用方法,才知道后面的代码框架要怎么搭;然后是明确SDK的职能范围:需要能处理用户行为、页面性能以及错误报警三类监控;最后是react、vue的项目,通常会做错误边界处理,要怎么接入我们自己的SDK。   如果觉得这篇文章对你有用,点赞关注是对我最大的鼓励!   作者:前端私教年年   链接:https://juejin.cn/post/7085679511290773534

没有基础在扣丁学堂HTML5培训多久能学会HTML5开发学习计算机软件开发的人都想要学好技术找一份高薪满意的好工作,因此在学习之前有没有基础,如何学习,多久能学成毕业等问题成为大家比较关心和在意的问题。本篇文章扣丁学堂小编就和读者们探讨扣丁学堂HTML5培训之Canvas玩转酷炫大波浪进度图实例本文介绍了HTML5Canvas玩转酷炫大波浪进度图结果,详细如下如上图所见,本文就是要实现上面那种结果。因为最近AlloyTouch要写一个下拉刷新的酷炫loading结果。所以扣丁学堂Python培训之PIL模块处理图片及中文验证码分享PIL是PythonImagingLibrary的简称,PIL是一个Python处理图片的库,提供了一系列模块和方法,比如裁切,平移,旋转,改变尺寸等等。已经是Python平台事实Java培训之人们对Java的误解分享关于人们对Java存在的误解可能每个人都会有一些,今天就跟扣丁学堂小编一块来看一下人们对Java的误解都有哪些吧。扣丁学堂Java培训讲师分析,人们对Java的误解有1。SysteJava视频教程之Java程序在什么情形下会挂掉小编想问一下大家知不知道Java程序在什么情形下会挂掉?有哪些小伙伴曾经碰到过Java程序挂掉的情况?本篇文章扣丁学堂Java培训机构小编就和读者们一块来看一下这个问题。在本例中,迪士尼计划裁员32000人意味着什么?近日一则新闻上了热搜美国华特迪士尼公司因新冠肺炎疫情持续打击其公园和度假村业务,计划在2021年3月底前裁员32000人。这意味着,有3。2万人的饭碗一下子被砸了,多少个家庭失去了Python分析北京市蛋壳公寓租房数据前言近期,蛋壳公寓爆雷事件持续发酵,期间因拖欠房东房租与租客退款,蛋壳公寓陷入讨债风波,全国多地蛋壳公寓办公区域出现大规模解约事件,而作为蛋壳公寓总部所在地北京,自然首当其冲。为了HTMLCSS新手快速入门教程源码HTMLCSS入门html和css的关系学习web前端开发基础技术需要掌握HTMLCSSJavaScript语言。下面我们就来了解下这三门技术都是用来实现什么的HTML是网页内容的HTMLCSS新手快速入门教程源码HTMLCSS入门HTMLCSS新手快速入门教程源码html和css的关系学习web前端开发基础技术需要掌握HTMLCSSJavaScript语言。下面我们就来了解下这三门技术都是Windows下MySQL数据库详细安装教程本教程以mysql5。5。40win64为例。1。选择合适的MySQL安装版本这是mysql5。5。40版本安装包。点击安装包,开始安装。2。基本上都是下一步3。同意软件安装协议4想要报考红帽Redhat认证要什么条件?Redhat认证包括6类1RHCSA英文全称RedHatCertifiedSystemAdministrator,中文全称红帽认证系统管理员2RHCE英文全称RedHatCerti
阿里巴巴启动大规模回购背后有三大积极信号3月22日美股收盘后,阿里巴巴宣布将股份回购规模由150亿美元扩大至250亿美元,有效期2年(截至2024年3月)。这已经是过去三个季度以来,阿里巴巴第二次扩大回购规模。2020年拼多多,装不下去了作者张生来源鸣金网砍不动的最后一刀,终于砍到自己身上。无数人的怒吼,已经将拼多多淹没!一hr拼多多永远也砍不完的最后一刀,到底还差多少刀?对这个困扰无数人的究极问题,有人就是不信邪超级小桀回应拼多多6万人砍单失败超级小桀回应拼多多6万人砍单失败今日头条像这种就是为了获取流量和点击率,找的人少了没有提出来钱就是人少,人多的时候反而是还差几个人就能提现,这样既可以获取流量和点击率,而且还可以变科技部拟规定不得向境外提供我国人类遗传资源22日,科学技术部下发关于公开征求人类遗传资源管理条例实施细则(征求意见稿)意见的通知。根据实施细则,人类遗传资源材料是指含有人体基因组基因等遗传物质的器官组织细胞等遗传材料。实施编程小技巧阿拉伯数字转中文汉字的Java方法之前做财务相关的系统时,阿拉伯数字需要转换成中文汉字。当时知识储备不足。一直没有满意的方案。今天特意思考这个问题,写下此方法,到目前为止算是最满意的方案了。importjava。u3月22日晚A股新能源上市公司利好消息1捷强装备(300875)接待银河证券等多家机构调研。2天顺风能(002531)去年陆上行业公开招标超50GW加上不需要招标项目预计风电行业全年陆上装机5060GW。3东方电缆(6海螺水泥10亿成立光伏科技公司加码新能源布局双碳及电价市场化改革背景下,水泥行业龙头海螺水泥(600585)动作频频,持续加码新能源领域布局。持续加码新能源布局企查查APP显示,3月21日,凤阳海螺光伏科技有限公司成立,法定算法时代即将落幕?官媒正式发声,早该这样了时至今日,我国的互联网行业已经发展了二十多年,可以说已经完全进入我们的日常生活。比如网购,且不说成年人,就连老年人甚至是小孩都已经熟知,对于相关的APP使用自如。而年轻人对于互联网艾融软件入选首批国家特色化示范性软件学院合作企业多年研发投入占营收比重超10挖贝网3月22日,北交所金融科技第一股艾融软件(830799)入选教育部办公厅工业和信息化部办公厅首批特色化示范性软件学院合作企业。数据显示,公司持续多年研发投入占营收比重超过10中国5G用户达到3。84亿占比23。3中新社北京3月22日电(记者刘育英)据最新统计,截至2022年2月末,中国三家基础电信企业5G移动电话用户达3。84亿户,比上年末净增2905万户,占移动电话用户总数的23。3。中百公里油耗2。1L,零百加速6。7秒,适时四驱,体验奥迪A6LPHEV在乘用车市场,随着新能源汽车的渗透率越来越高,各品牌都加速了在这个领域的布局,豪华品牌BBA也不例外。奥迪A6LPHEV,作为奥迪旗下的插电式混合动力中大型轿车,产品实力如何呢?当