当前位置: 首页 > news >正文

济南网站建设群上海哪些做网站

济南网站建设群,上海哪些做网站,网站建设公司的市场营销方案模板下载,网站域名实名认证通知目录 一、从0开始 二、上报数据方法 三、上报时机 四、性能数据收集上报 收集上报FP 收集上报FCP 收集上报LCP 收集上报DOMContentLoaded 收集上报onload数据 收集上报资源加载时间 收集上报接口请求时间 五、错误数据收集上报 收集上报资源加载错误 收集上报js错…目录 一、从0开始 二、上报数据方法 三、上报时机 四、性能数据收集上报 收集上报FP 收集上报FCP 收集上报LCP 收集上报DOMContentLoaded 收集上报onload数据 收集上报资源加载时间 收集上报接口请求时间 五、错误数据收集上报 收集上报资源加载错误 收集上报js错误 收集上报promise错误 六、行为数据收集上报 收集上报pv、uv 页面上报停留时长 用户点击上报 七、改造完善四维监控类 总结 可参考文章 参考资料 在我已有的职业生涯中前端确实大多数时候是在裸奔的这是这篇文章被我写出来的理由。而且现在是一个数据时代没有数据很多时候就没有反馈没有下一步也就没有进步。 一个完整的前端监控平台包括三个部分数据采集与上报、数据整理和存储、数据展示。本文只写数据采集与上报部分。 数据采集 (1).png 数据上报.png 一、从0开始 名字很重要一个好的名字会让使用者很容易记住会让使用者莫名产生一种自豪感会更容易传播如果名字能够切合某种大道更能带来顺理成章的效果。本文的监控SDK就叫四维吧寓意上帝视角。全写four-dimension简写为FD。 class FourDimension {constructor() {this.init()}// 初始化init() {} }定义一个 FourDimension 类目前有构造函数构造函数无参数。只有init方法用以初始化类。init方法用以性能、错误、行为数据收集。 二、上报数据方法 业界比较成熟的方案使用1x1像素的gif图片上报本文也是。同时也可以使navigator.sendBeaconnavigator.sendBeacon是一个用于发送少量数据到服务器的浏览器API。它有以下几个优点 异步和非阻塞navigator.sendBeacon 是异步的它不会阻塞浏览器的其他操作。这对于性能监控来说非常重要因为都不希望监控的过程影响到页面的性能。 在页面卸载时仍然可以发送数据当用户离开页面例如关闭页面或者导航到其他页面时navigator.sendBeacon仍然可以发送数据。这对于捕获和上报页面卸载前的最后一些性能数据来说非常有用。 低优先级navigator.sendBeacon 发送的请求是低优先级的它不会影响到页面的其他网络请求。 简单易用navigator.sendBeacon 的API非常简单只需要提供上报的URL和数据就可以发送请求。 与此同时navigator.sendBeacon 也有一些限制。例如它只能发送POST请求不能发送GET请求。而且它发送的请求没有返回值不能接收服务器的响应。 最后一些旧的浏览器可能不支持 navigator.sendBeacon。因此在使用 navigator.sendBeacon 时需要根据实际情况进行兼容性处理。 本文的方案是优先navigator.sendBeacon降级使用1x1像素gif图片根据实际情况需要采用xhr。 创建report.js增加上传方法 import {isSupportSendBeacon} from ./util// 如果浏览器不支持 sendBeacon就使用图片打点 const sendBeacon  (function(){if(isSupportSendBeacon()){return window.navigator.sendBeacon.bind(window.navigator)}const reportImageBeacon  function(url, data){reportImage(url, data)}return reportImageBeacon })()export function reportImage(url, data) {const img  new Image();img.src  url  ?reportData  encodeURIComponent(JSON.stringify(data)); }三、上报时机 参考其它文章上报时机选择对当前页面影响最小的方案 上报时机有三种 采用 requestIdleCallback/setTimeout 延时上报。 在 beforeunload 回调函数里上报。 缓存上报数据达到一定数量后再上报。 将三种方式结合一起上报 先缓存上报数据缓存到一定数量后利用 requestIdleCallback/setTimeout 延时上报。在页面离开时统一将未上报的数据进行上报。 创建缓存文件cache.js import { deepCopy } from ./utilconst cache  []export function getCache() {return deepCopy(cache) }export function addCache(data) {cache.push(data) }export function clearCache() {cache.length  0 }其中deepCopy export function deepCopy(target) {if (typeof target  object) {const result  Array.isArray(target) ? [] : {}for (const key in target) {if (typeof target[key]  object) {result[key]  deepCopy(target[key])} else {result[key]  target[key]}}return result}return target }修改上传文件report.js import { addCache, getCache, clearCache } from ./cache import config from ../config import {isSupportSendBeacon, generateUniqueID} from ./utilconst sendBeacon  (function(){if(isSupportSendBeacon()){return window.navigator.sendBeacon.bind(window.navigator)}const reportImageBeacon  function(url, data){reportImage(url, data)}return reportImageBeacon })()const sessionID  generateUniqueID() export function report(data, isImmediate  false) {if (!config.reportUrl) {console.error(请设置上传 url 地址)}const reportData  JSON.stringify({id: sessionID,appID: config.appID,userID: config.userID,data,})if (isImmediate) {sendBeacon(config.reportUrl, reportData)return}if (window.requestIdleCallback) {window.requestIdleCallback(()  {sendBeacon(config.reportUrl, reportData)}, { timeout: 3000 })} else {setTimeout(()  {sendBeacon(config.reportUrl, reportData)})} }let timer  null export function lazyReportCache(data, timeout  3000) {addCache(data)clearTimeout(timer)timer  setTimeout(()  {const data  getCache()if (data.length) {report(data)clearCache()}}, timeout) }export function reportWithXHR(data) {// 1. 创建 xhr 对象let xhr  new XMLHttpRequest()// 2. 调用 open 函数xhr.open(POST, config.reportUrl)// 3. 调用 send 函数xhr.send(JSON.stringify(data)) }export function reportImage(url, data) {const img  new Image();img.src  url  ?reportData  encodeURIComponent(JSON.stringify(data)); }其中config.js文件 const config  {reportUrl: http://localhost:8000/reportData,projectName: fd-example }export function setConfig(options) {for (const key in config) {if (options[key]) {config[key]  options[key]}} } export default config四、性能数据收集上报 根据最初的规划性能监控需要收集的数据指标需要有FP、FCP、LCP、DOMContentLoaded、onload、资源加载时间、接口请求时间。 收集FP、FCP、LCP、资源加载时间具体是利用浏览器Performance API。关于Performance API可以参考Performance[1] 收集上报FP FPFirst Paint首次绘制即浏览器开始绘制页面的时间点。这包括了任何用户自定义的绘制它是渲染任何文本、图像、SVG等的开始时间 import { getPageURL, isSupportPerformanceObserver } from ../utils/util import { lazyReportCache } from ../utils/reportexport default function observePaint() {if (!isSupportPerformanceObserver()) returnconst entryHandler  (list)  {        for (const entry of list.getEntries()) {if (entry.name  first-paint) {observer.disconnect()}const json  entry.toJSON()delete json.durationconst reportData  {...json,subType: entry.name,type: performance,pageURL: getPageURL(),}lazyReportCache(reportData)}}const observer  new PerformanceObserver(entryHandler)// buffered 属性表示是否观察缓存数据也就是说观察代码添加时机比事情触发时机晚也没关系。observer.observe({ type: paint, buffered: true })}代码中observer.disconnect()是PerformanceObserver对象的一个方法用于停止观察性能指标并断开与回调函数的连接。 事实上 observer.observe({ type: paint, buffered: true })包含两种性能指标first-contentful-paint和first-paint。 当调用observer.disconnect()方法时PerformanceObserver对象将停止观察性能指标并且不再接收任何性能指标的更新。与此同时与回调函数的连接也会被断开即使有新的性能指标数据产生也不会再触发回调函数。 这个方法通常在不再需要观察性能指标时调用以避免不必要的资源消耗。 收集上报FCP FCPFirst Contentful Paint首次内容绘制即浏览器首次绘制DOM内容的时间点如文本、图像、SVG等。 看起来FCP和FP一致其实还是有区别的 FCPFirst Contentful PaintFCP是指页面上首次渲染任何文本、图像、非空白的canvas或SVG的时间点。它表示了用户首次看到页面有实际内容的时间即页面开始呈现有意义的内容的时间点。 FPFirst PaintFP是指页面上首次渲染任何内容的时间点包括背景颜色、图片、文本等。它表示了页面开始呈现任何可视化内容的时间但不一定是有意义的内容。 简而言之FCP关注的是页面上首次呈现有意义内容的时间点而FP关注的是页面上首次呈现任何可视化内容的时间点。FCP更关注用户感知的页面加载时间因为它表示用户可以开始阅读或与页面进行交互的时间点。而FP则更关注页面开始渲染的时间点无论内容是否有意义 import { getPageURL, isSupportPerformanceObserver } from ../utils/util import { lazyReportCache } from ../utils/reportexport default function observePaint() {if (!isSupportPerformanceObserver()) returnconst entryHandler  (list)  {        for (const entry of list.getEntries()) {if (entry.name  first-contentful-paint) {observer.disconnect()}const json  entry.toJSON()delete json.durationconst reportData  {...json,subType: entry.name,type: performance,pageURL: getPageURL(),}lazyReportCache(reportData)}}const observer  new PerformanceObserver(entryHandler)// buffered 属性表示是否观察缓存数据也就是说观察代码添加时机比事情触发时机晚也没关系。observer.observe({ type: paint, buffered: true })}收集上报LCP LCPLargest Contentful Paint最大内容绘制即视口中最大的图像或文本块的渲染完成的时间点 import { getPageURL, isSupportPerformanceObserver } from ../utils/util import { lazyReportCache } from ../utils/reportexport default function observeLCP() {if (!isSupportPerformanceObserver()) {return}const entryHandler  (list)  {if (observer) {observer.disconnect()}for (const entry of list.getEntries()) {const json  entry.toJSON()delete json.durationconst reportData  {...json,target: entry.element?.tagName,name: entry.entryType,subType: entry.entryType,type: performance,pageURL: getPageURL(),}lazyReportCache(reportData)}}const observer  new PerformanceObserver(entryHandler)observer.observe({ type: largest-contentful-paint, buffered: true }) }收集上报DOMContentLoaded DOMContentLoaded当HTML文档被完全加载和解析完成后DOMContentLoaded事件被触发无需等待样式表、图像和子框架的完成加载 import { lazyReportCache } from ../utils/reportexport default function observerLoad() {[DOMContentLoaded].forEach(type  onEvent(type)) }function onEvent(type) {function callback() {lazyReportCache({type: performance,subType: type.toLocaleLowerCase(),startTime: performance.now(),})window.removeEventListener(type, callback, true)}window.addEventListener(type, callback, true) }收集上报onload数据 onload当所有需要立即加载的资源如图片和样式表已加载完成时的时间点 import { lazyReportCache } from ../utils/reportexport default function observerLoad() {[load].forEach(type  onEvent(type)) }function onEvent(type) {function callback() {lazyReportCache({type: performance,subType: type.toLocaleLowerCase(),startTime: performance.now(),})window.removeEventListener(type, callback, true)}window.addEventListener(type, callback, true) }收集上报资源加载时间 收集资源加载时间 observer.observe({ type: resource, buffered: true })我在想什么是资源加载时间应该就是下面的entry.duration的。我觉得写监控SDK很有意义可以更加深入的学习浏览器模型。了解浏览器是怎么看待各种html文件资源的 import { executeAfterLoad, isSupportPerformanceObserver} from ../utils/util import { lazyReportCache } from ../utils/reportexport default function observeEntries() {executeAfterLoad(()  {observeEvent(resource)}) }export function observeEvent(entryType) {function entryHandler(list) {const data  list.getEntries()for (const entry of data) {if (observer) {observer.disconnect()}lazyReportCache({name: entry.name, // 资源名称subType: entryType,type: performance,sourceType: entry.initiatorType, // 资源类型duration: entry.duration, // 资源加载耗时dns: entry.domainLookupEnd - entry.domainLookupStart, // DNS 耗时tcp: entry.connectEnd - entry.connectStart, // 建立 tcp 连接耗时redirect: entry.redirectEnd - entry.redirectStart, // 重定向耗时ttfb: entry.responseStart, // 首字节时间protocol: entry.nextHopProtocol, // 请求协议responseBodySize: entry.encodedBodySize, // 响应内容大小responseHeaderSize: entry.transferSize - entry.encodedBodySize, // 响应头部大小resourceSize: entry.decodedBodySize, // 资源解压后的大小startTime: performance.now(),})}}let observerif (isSupportPerformanceObserver()) {observer  new PerformanceObserver(entryHandler)observer.observe({ type: entryType, buffered: true })} }收集上报接口请求时间 这里通过覆写原生xhr对象方法对方法做拦截实现接口时间收集以及上报 import { originalOpen, originalSend, originalProto } from ../utils/xhr import { lazyReportCache } from ../utils/reportfunction overwriteOpenAndSend() {originalProto.open  function newOpen(...args) {this.url  args[1]this.method  args[0]originalOpen.apply(this, args)}originalProto.send  function newSend(...args) {this.startTime  Date.now()const onLoadend  ()  {this.endTime  Date.now()this.duration  this.endTime - this.startTimeconst { status, duration, startTime, endTime, url, method }  thisconst reportData  {status,duration,startTime,endTime,url,method: (method || GET).toUpperCase(),success: status  200  status  300,subType: xhr,type: performance,}lazyReportCache(reportData)this.removeEventListener(loadend, onLoadend, true)}this.addEventListener(loadend, onLoadend, true)originalSend.apply(this, args)} }export default function xhr() {overwriteOpenAndSend() }五、错误数据收集上报 根据最初的规划需要收集资源加载错误、js错误和promise错误。 收集上报资源加载错误 收集 JavaScript、CSS 和图片的加载错误使用window.addEventListener监听错误 import { lazyReportCache } from ../utils/report import { getPageURL } from ../utils/utilexport default function error() {// 捕获资源加载失败错误 js css img...window.addEventListener(error, e  {const target  e.targetif (!target) returnif (target.src || target.href) {const url  target.src || target.hreflazyReportCache({url,type: error,subType: resource,startTime: e.timeStamp,html: target.outerHTML,resourceType: target.tagName,paths: e.path.map(item  item.tagName).filter(Boolean),pageURL: getPageURL(),})}}, true) }收集上报js错误 收集 JavaScript 错误可以使用 window.onerror 或者 window.addEventListener(error, callback) import { lazyReportCache } from ../utils/report import { getPageURL } from ../utils/utilexport default function error() {// 监听 js 错误window.onerror  (msg, url, line, column, error)  {lazyReportCache({msg,line,column,error: error.stack,subType: js,pageURL: url,type: error,startTime: performance.now(),})}}说明一下window.onerror无法捕获资源加载错误所以这里可以单独拿来监听js错误。 收集上报promise错误 收集 Promise 错误可以使用 window.addEventListener(unhandledrejection, callback) import { lazyReportCache } from ../utils/report import { getPageURL } from ../utils/utilexport default function error() {// 监听 promise 错误 缺点是获取不到列数据window.addEventListener(unhandledrejection, e  {lazyReportCache({reason: e.reason?.stack,subType: promise,type: error,startTime: e.timeStamp,pageURL: getPageURL(),})})}为了减少对html文件代码的干扰错误收集可以添加一个缓存代理具体参考字节前端监控实践[2]。 六、行为数据收集上报 根据最初的规划行为数据收集pv、uv页面停留时长用户点击。 收集上报pv、uv 收集 pvPage View页面浏览量和 uvUnique Visitor独立访客数据需要在每次页面加载时发送一个请求到服务器然后在服务器端进行统计 import { lazyReportCache } from ../utils/report import getUUID from ./getUUID import { getPageURL } from ../utils/utilexport default function pv() {lazyReportCache({type: behavior,subType: pv,startTime: performance.now(),pageURL: getPageURL(),referrer: document.referrer,uuid: getUUID(),}) }这里只能收集了pv数据uv数据统计需要在服务端进行。 页面上报停留时长 收集页面停留时长可以在页面加载时记录一个开始时间然后在页面卸载时记录一个结束时间两者的差就是页面的停留时长。这个计算逻辑可以放在beforeunload事件里做 import { report } from ../utils/report import { onBeforeunload, getPageURL } from ../utils/util import getUUID from ./getUUIDexport default function pageAccessDuration() {onBeforeunload(()  {report({type: behavior,subType: page-access-duration,startTime: performance.now(),pageURL: getPageURL(),uuid: getUUID(),}, true)}) }用户点击上报 收集用户点击事件可以使用 addEventListener 来监听 click 事件这里借助了冒泡 import { lazyReportCache } from ../utils/report import { getPageURL } from ../utils/util import getUUID from ./getUUIDexport default function onClick() {[mousedown, touchstart].forEach(eventType  {let timerwindow.addEventListener(eventType, event  {clearTimeout(timer)timer  setTimeout(()  {const target  event.targetconst { top, left }  target.getBoundingClientRect()lazyReportCache({top,left,eventType,pageHeight: document.documentElement.scrollHeight || document.body.scrollHeight,scrollTop: document.documentElement.scrollTop || document.body.scrollTop,type: behavior,subType: click,target: target.tagName,paths: event.path?.map(item  item.tagName).filter(Boolean),startTime: event.timeStamp,pageURL: getPageURL(),outerHTML: target.outerHTML,innerHTML: target.innerHTML,width: target.offsetWidth,height: target.offsetHeight,viewport: {width: window.innerWidth,height: window.innerHeight,},uuid: getUUID(),})}, 500)})}) }七、改造完善四维监控类 将性能数据、错误数据、行为数据入口文件的收集方法在监控类四维init方法内初始化 import performance from ./performance/index import behavior from ./behavior/index import error from ./error/indexclass FourDimension {constructor() {this.init()}// 初始化init() {performance()error()behavior()} }new FourDimension().init()在具体使用过程中采用异步加载的方式引入。 总结 如果没有具体数据能够证明这个策略是优的那么就从理论上选优的。这也是我写这篇文章的理论支撑之一。因为毕竟没有真实数据做验证。 还有一个支撑是先模仿理解别人的再理出自己的思路而且写文章也是督促自己学习的一种方式。本文大量参考了前端监控 SDK 的一些技术要点原理分析 [3]这篇文章。写着写着发现关键是数据收集和上报方式具体上报数据模型以及上报方式需要在真实场景中研究迭代。 写这篇文章的一个收获正如前文说的可以更加深入的了解到浏览器对html文件各种资源是如何看待的。前端开发或者开发这件事一直在和逻辑、数据打交道但是涉及到底层逻辑的量化指标我认为并不多。而写监控就必须要探索底层的量化指标这是一个很好的意义可以深入下去的意义。 当然另一个意义也说了任何事没有反馈则没有进步。监控就是反馈。 另外我想如果这种监控如果可视化就如同对人的监控一样就算是没有警报事件也能记录被监控对象的各种行为数据。一定会很有有意思。即使没有错误也能有一种可视化画面。 代码地址github.com/zhensg123/r…[4] 本文完。 可参考文章 前端监控 SDK 的一些技术要点原理分析[5] 一篇讲透自研的前端错误监控[6] 字节前端监控实践[7] 参考资料 [1] https://developer.mozilla.org/zh-CN/docs/Web/API/Performance: https://link.juejin.cn?targethttps%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FPerformance [2] https://juejin.cn/post/7195496297150709821#heading-17: https://juejin.cn/post/7195496297150709821#heading-17 [3] https://juejin.cn/post/7017974567943536671: https://juejin.cn/post/7017974567943536671 [4] https://github.com/zhensg123/rareRecord/tree/main/fourDemension: https://link.juejin.cn?targethttps%3A%2F%2Fgithub.com%2Fzhensg123%2FrareRecord%2Ftree%2Fmain%2FfourDemension [5] https://juejin.cn/post/7017974567943536671: https://juejin.cn/post/7017974567943536671 [6] https://juejin.cn/post/6987681953424080926: https://juejin.cn/post/6987681953424080926 [7] https://juejin.cn/post/7195496297150709821: https://juejin.cn/post/7195496297150709821
http://www.pierceye.com/news/983914/

相关文章:

  • 论坛网站建设联系方式成都网站设计制作价格
  • 网页网站建设的ppt模板下载响应式网站项目
  • 做网站在哪里可以找到高清壁纸北京响应式网站
  • 企业网站建设门户网站建设费的摊销年限
  • 模板网站的域名是什么网站源代码程序
  • 网站空间多久续一次费长春网站制作设计
  • 网站制作价格低广西网络电视
  • 平台网站建设收费烟台网站的优化
  • 如何做提卡网站vue.js wordpress
  • 国家网站备案查询系统wordpress 主题 简洁
  • 建设商业网站html什么意思
  • 网站专题建设方案江苏省建设厅网站 杨洪海
  • 通化网站建设公司南江县住房和城乡建设局网站
  • 网站的外链是什么软件开发与网站开发的区别
  • 学做网站论坛vip账户了解网站开发的背景
  • 做3个网站需要多大的服务器科凡建站
  • 网站设计制作音乐排行榜44555pd永久四色端口
  • 网站优化方案教程如何注册chn域名网站
  • 怎样建设免费网站个别网站网速慢怎么做
  • 网页设计制作音乐排行榜一键seo提交收录
  • 网站推广要我营业执照复印件conoha wordpress
  • 免费行情软件app网站排行高质量外链网站
  • 免费解析网站制作网站开发项目实战视频
  • 柳州网站建设工作室基金会网站开发方案
  • 龙海网站建设微网站如何建设
  • 手机视频网站怎么做贵阳专业做网站
  • 网站建设题库vps上的网站运行太慢
  • 化妆品网站优化沧州网站制作公司
  • 专业优定软件网站建设上海seo服务
  • 网站充值怎么做的c2c平台的产品类型