摘要:今天我們來聊聊前端的監控我們為什么需要前端監控為了獲取用戶行為以及跟蹤產品在用戶端的使用情況,并以監控數據為基礎,指明產品優化方向前端監控分為三類性能項目數據監控異常監控性能監控衡量前端的性能的指標是時間那么如何監測時間呢,瀏覽器給我們提
今天我們來聊聊前端的監控
我們為什么需要前端監控 ?
為了獲取用戶行為以及跟蹤產品在用戶端的使用情況,并以監控數據為基礎,指明產品優化方向
前端監控分為三類
性能項目
數據監控
異常監控
性能監控- 衡量前端的性能的指標是時間
那么如何監測時間呢, 瀏覽器給我們提供了一個 API performance
來看看里面都有什么吧
它的屬性 timing 是一個PerformanceTiming 對象 , 包含了延遲相關的性能,timing里的屬性基本都是成雙成對的 都是以xxxstart --- xxxend end跟start的時間差就是我們所需要的信息
那么我們來捋一捋網頁打開到關閉 都有哪些時間戳記錄下來,看一張網頁加載流程圖
首先是navigationStart 就是地址欄開始加載 期間會執行unload 卸載上一個網頁的內容 如果有重定向(同域名),就開始重定向。
fetchStart 抓取開始 頁面開始加載
domainLookupStart dns 解析開始
domainLookupEnd dns 解析結束
connectStart tcp 握手開始
connectEnd 建立連接
requestStart 請求頁面開始
responseStart 響應開始
responseEnd 響應結束
domloading dom開始加載
domInteractive dom結構樹加載完成(src外鏈資源未完成)
domcontentLoaded($(function(){}))
domComplete dom 加載完畢 外鏈資源加載完畢
loadevent (window.onload=function(){} 里面的代碼加載完畢)
那么我們開始寫個監控吧 先起一個服務
serve.js
let Koa = require("koa") let Server = require("koa-static") let path = require("path") let app = new Koa() app.use(Server(path.resolve(__dirname))) app.listen(3000,function(){ console.log("Server is running on port 3000") })
將serve作為靜態資源目錄 服務起在端口3000
再新建performance.js
performance.js
// 性能監控 let time = ()=>{ let timing = performance.timing let data = { prevPage: timing.fetchStart - timing.navigationStart , // 上一個頁面卸載到新頁面的時間 redirect: timing.redirectEnd - timing.redirectStart , // 重定向時長 dns: timing.domainLookupEnd - timing.domainLookupStart, // dns 解析時長 tcp: timing.connectEnd - timing.connectStart ,// tcp 鏈接時長 respone: timing.responseEnd - timing.requestStart, // 響應時長 ttfb: timing.responseStart - timing.navigationStart, // 首字節接收到 的時長 domReady:timing.domInteractive - timing.domLoading, // dom 準備時長 whiteScreen:timing.domLoading - timing.navigationStart, // 白屏時間 dom:timing.domComplete - timing.domLoading, // dom解析時間 load:timing.loadEventEnd - timing.loadEventStart, total:timing.loadEventEnd - timing.navigationStart } return data } // 因為檢測代碼在load里執行 所以此時load事件未完成 檢測不到load的時間 所以我們需要設置一個定時器來監聽load完成 let timeout = (cb)=>{ let timer; let check = ()=>{ // 加載完畢后才有performance.timing.loadEventEnd if(performance.timing.loadEventEnd){ timer = null cb() }else{ timer = setTimeout(check,100) } } window.addEventListener("load",check,false) } let domReady = (cb)=>{ let timer; let check = ()=>{ // performance.timing.domInteractive if(performance.timing.domInteractive){ timer = null cb() }else{ timer = setTimeout(check,100) } } window.addEventListener("DOMContentLoaded",check,false) } let _performance = { init(cb){ //有可能domloaded 并未加載好 用戶就關閉網頁了 這種情況也希望監聽到 domReady(()=>{ let data = time() data.type = "domReady" cb(data) }) // dom完全加載完畢 timeout(()=>{ let data = time() data.type = "loaded" cb(data) }) } } // 通過_performance.init(cb) 獲取到監控數據 _performance.init((data)=>{console.log(data)})
html 引入performance.js
運行結果為:
然后發送圖片到服務器
// 通過_performance.init(cb) 獲取到監控數據 let formatter = (data)=>{ let arr = [] for(key in data){ arr.push(`${key}=${data[key]}`) } return arr.join("&") } _performance.init((data)=>{ // 然后我們創建一張空圖片把數據發給服務器 let img = new Image() img.src = "/p.gif?" + formatter(data) })監控頁面資源加載情況
想要監控資源就得獲取到__proto__ 上的getEntriesByType("resource")方法
獲取到的是個數組 包含了資源請求的時間 名字type 之類的 我們所做的就是拿區我們自己需要的東西
performance.js
//代碼省略 let resource = performance.getEntriesByType("resource") let data = resource.map(_=>{ return { name:_.name, initatorType:_.initiatorType, duration:_.duration } }) cb(data)ajax請求監控
ajax 請求監控就簡單了
performance.js
// 為了獲取到我們所需要的參數 我們改寫一下 XMLHttpRequest.prototype.open(method,url,isAsync) let ajax = { init(cb){ let xhr = window.XMLHttpRequest // 保存原來的open方法 let oldOpen = xhr.prototype.open console.log(oldOpen) xhr.prototype.open = function(method,url,isAsync = true,...args){ this.info = {method,url,isAsync,message:args} return oldOpen.apply(this,arguments) } let oldSend = xhr.prototype.send xhr.prototype.send = function(value){ let start = Date.now() let fn = (type) => () =>{ this.info.time = Date.now() - start this.info.requestSize = value ? value.length : 0 this.info.responeSize = this.responseText.length this.info.type = type cb(this.info) } this.addEventListener("load",fn("success"),false) this.addEventListener("error",fn("error"),false) this.addEventListener("abort",fn("abort"),false) return oldSend.apply(this,arguments) } } } ajax.init((data)=>{ console.log(data) })
index.html
// ajax 請求監控 原生ajax var request = new XMLHttpRequest(); // 新建XMLHttpRequest對象 request.onreadystatechange = function () { // 狀態發生變化時,函數被回調 if (request.readyState === 4) { // 成功完成 // 判斷響應結果: if (request.status === 200) { // 成功,通過responseText拿到響應的文本: } else { // 失敗,根據響應碼判斷失敗原因: } } else { // HTTP請求還在繼續... } } // 發送請求: request.open("GET", "/api/categories",true,"fet"); request.send();
結果如下
主要是通過window.onerror 事件來捕獲
let errorCatch = { init(cb){ window.addEventListener("error",function(message, source, lineno, colno, error) { this.info = {} let stack = error.stack; let matchUrl = stack.match(/http://[^ ]*/)[0] // 獲取報錯路徑 this.info.filename = matchUrl.match(/http://(?:S*).js/) ? matchUrl.match(/http://(?:S*).js/)[0]:"html" // 獲取報錯文件; let [,row,col] = stack.match(/:(d+):(d+)/) // 獲取報錯行 列 this.info = { message:error.message, name:error.name, filename:this.info.filename, //有可能是html里的js報錯 row, col, // 真實上線的時候 需要source-map 去找到真正的行跟列 } cb(this.info) },true) } } errorCatch.init(data=>{console.dir(data)})
需要值得注意的是
promise 無法用此方法捕獲??! 需要另行監聽另外的事件
另外不同域的js文件不能用此方法捕獲詳細 具體查看https://www.jianshu.com/p/315...
主要方式是在document上監聽事件 通過事件委托獲取事件對象 封裝info 傳給后臺
綜上所訴 大致就是這樣 這里只是簡單的介紹了下 需要深入了解的小伙伴請自行尋找相關資料, 比如火焰圖之類的
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101777.html
摘要:性能統計有助于幫我們檢測網站的用戶體驗。這樣,我們就輕輕松松的統計到了首屏時間。下一章,我們將繼續聊聊百度移動版首頁那些事。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼): https://segmentfault.com/blog/frontenddriver 上一篇文章我們討論了,如何進行前端日志打點統計: https://segm...
摘要:性能統計有助于幫我們檢測網站的用戶體驗。這樣,我們就輕輕松松的統計到了首屏時間。下一章,我們將繼續聊聊百度移動版首頁那些事。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼): https://segmentfault.com/blog/frontenddriver 上一篇文章我們討論了,如何進行前端日志打點統計: https://segm...
摘要:所以今天,就和大家一起聊一聊前端的安全那些事兒。我們就聊一聊前端工程師們需要注意的那些安全知識。殊不知,這不僅僅是違反了的標準而已,也同樣會被黑客所利用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog... 隨著互聯網的發達,各種WEB應用也變得越來越復雜,滿足了用戶的各種需求...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼作為現代應用,的大量使用,使得前端工程師們日常的開發少不了拼裝模板,渲染模板。我們今天就來聊聊,拼裝與渲染模板的那些事兒。一改俱改,一板兩用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog...
閱讀 814·2021-11-25 09:43
閱讀 1681·2021-09-29 09:42
閱讀 1897·2019-08-30 15:55
閱讀 3418·2019-08-30 15:54
閱讀 2623·2019-08-30 13:20
閱讀 3506·2019-08-29 13:25
閱讀 916·2019-08-28 18:03
閱讀 1783·2019-08-26 13:44