【大前端攻城獅之路】百度愛番番前端性能監(jiān)控體系方案設(shè)計(jì)
一、背景
愛番番大前端整體面臨以下問題:
-
Metrics:URL的RED指標(biāo)不全。URL不全,ERROR缺失,Duration分位置缺失。整體實(shí)效性為T+1。無法及時(shí)感知問題。只對(duì)基本頁面級(jí)別的讀操作進(jìn)行了監(jiān)控。
-
Tracing:Trace無法全端串聯(lián),直接影響具體case的跟進(jìn)。無前端Trace。
-
Logging:無Log。Sentry的Error信息目前僅PC接入。且未進(jìn)行實(shí)際使用;和trace無法打通。
-
報(bào)警:對(duì)于異常數(shù)據(jù)缺乏有效報(bào)警。
二、目標(biāo)
-
Metrics目標(biāo):RED指標(biāo),自定義Metrics
-
Tracing目標(biāo):全端單動(dòng)作追蹤
-
Logging目標(biāo):Error級(jí)別Log具備。單Traceid和Log能夠?qū)崿F(xiàn)串聯(lián)

2.1 核心目標(biāo)
從全局問題出發(fā),能夠洞察統(tǒng)計(jì)性的頁面url真實(shí)RED指標(biāo),以及可以做操作流任意階段之間的統(tǒng)計(jì)性耗時(shí)分析。從個(gè)案問題出發(fā),能夠基于用戶id進(jìn)行任意一次全端調(diào)用鏈追蹤。
具體地:
-
頁面級(jí)別性能監(jiān)控。可包含條件檢索和正常頁面刷新。包含RED
-
能夠基于用戶id進(jìn)行任意一次全端調(diào)用鏈追蹤。
-
可分析一個(gè)操作流任意階段之間的統(tǒng)計(jì)性耗時(shí)。
-
準(zhǔn)實(shí)時(shí)呈現(xiàn)。數(shù)據(jù)延時(shí)小于5min。
-
可區(qū)分來源、地域、設(shè)備等核心信息
-
寫請(qǐng)求性能監(jiān)控。包含新建、編輯、刪除。包含RED
2.2 目標(biāo)抽象
本質(zhì)上,抽象為AggrEvent、Event、Trace、Span四個(gè)概念。Transaction用來做純埋點(diǎn),此處暫不需要。
-
帶TraceID(可被覆蓋)和TimeStamp信息的Event
-
全端Trace下的調(diào)用鏈。本質(zhì)上是前端的Event鏈路 + 服務(wù)端的Span鏈路串聯(lián)而成。
-
考慮到批量傳輸性能。采用AggrEvent進(jìn)行聚合發(fā)送。
三、 名詞解釋
- RED:RED方法是Weave Cloud在基于Google的“4個(gè)黃金指標(biāo)”的原則下結(jié)合Prometheus以及Kubernetes容器實(shí)踐,細(xì)化和總結(jié)的方法論,特別適合于云原生應(yīng)用以及微服務(wù)架構(gòu)應(yīng)用的監(jiān)控和度量。主要關(guān)注以下三種關(guān)鍵指標(biāo):
- (請(qǐng)求)速率:服務(wù)每秒接收的請(qǐng)求數(shù)。
- (請(qǐng)求)錯(cuò)誤:每秒失敗的請(qǐng)求數(shù)。
- (請(qǐng)求)耗時(shí):每個(gè)請(qǐng)求的耗時(shí)。
- optid(operate-id):一個(gè)操作唯一對(duì)應(yīng)的一個(gè)id。比如一次刷新,一次修改。
- reqid(request-id):?jiǎn)未握?qǐng)求唯一對(duì)應(yīng)的一個(gè)id。如果重試,則reqid設(shè)置為新id。一個(gè)optid可能會(huì)存在多個(gè)reqid。
- tid(tracing-id):貫穿服務(wù)端端調(diào)用鏈的唯一id。
- optType: 某一類操作定義。比如一次刷新,一次修改。
四、目標(biāo)拆解
4.1 Why
4.1.1 為什么要做大前端監(jiān)控體系?
獲取用戶行為以及跟蹤產(chǎn)品在用戶端的使用情況,并以監(jiān)控?cái)?shù)據(jù)為基礎(chǔ),指明產(chǎn)研優(yōu)化的方向。
4.1.2 收益是什么?
-
Metrics:對(duì)各端各頁面各場(chǎng)景RED指標(biāo)準(zhǔn)實(shí)時(shí)分析、可視化呈現(xiàn),打破前端監(jiān)控黑盒
-
Tracing:打通前后端調(diào)用鏈,能夠針對(duì)任意case進(jìn)行前后端鏈路分析,讓前端性能優(yōu)化有的放矢
-
Logging:對(duì)各端運(yùn)行時(shí)錯(cuò)誤進(jìn)行實(shí)時(shí)監(jiān)控報(bào)警,能通過日志最大程度還原用戶現(xiàn)場(chǎng)并定位問題,提升前端頁面穩(wěn)定性
4.2 What
4.2.1 監(jiān)控什么端?
愛番番現(xiàn)有產(chǎn)品各端:web,h5(瀏覽器、webview),Android,iOS,客戶端,小程序
4.2.2 監(jiān)控什么方向
(1) 數(shù)據(jù)監(jiān)控
數(shù)據(jù)監(jiān)控,顧名思義就是監(jiān)聽用戶的行為。常見的數(shù)據(jù)監(jiān)控包括:
-
PV/UV:PV(page view),即頁面瀏覽量或點(diǎn)擊量。UV:指訪問某個(gè)站點(diǎn)或點(diǎn)擊某條新聞的不同IP地址的人數(shù)
-
用戶在每一個(gè)頁面的停留時(shí)間
-
用戶通過什么入口來訪問該網(wǎng)頁
-
用戶在相應(yīng)的頁面中觸發(fā)的行為
統(tǒng)計(jì)這些數(shù)據(jù)是有意義的,比如我們知道了用戶來源的渠道,可以促進(jìn)產(chǎn)品的推廣,知道用戶在每一個(gè)頁面停留的時(shí)間,可以針對(duì)停留較長的頁面,增加廣告推送等等。
該方向主要為業(yè)務(wù)服務(wù),目前職責(zé)定位更符合神策埋點(diǎn)系統(tǒng)。
(2) 性能監(jiān)控
性能監(jiān)控指的是監(jiān)聽前端的性能,主要包括監(jiān)聽網(wǎng)頁或者說產(chǎn)品在用戶端的體驗(yàn)。常見的性能監(jiān)控?cái)?shù)據(jù)包括:
-
不同用戶,不同機(jī)型和不同系統(tǒng)下的首屏加載時(shí)間
-
白屏?xí)r間
-
http等請(qǐng)求的響應(yīng)時(shí)間
-
靜態(tài)資源整體下載時(shí)間
-
頁面渲染時(shí)間
-
頁面交互動(dòng)畫完成時(shí)間
這些性能監(jiān)控的結(jié)果,可以展示前端性能的好壞,根據(jù)性能監(jiān)測(cè)的結(jié)果可以進(jìn)一步的去優(yōu)化前端性能,比如兼容低版本瀏覽器的動(dòng)畫效果,加快首屏加載等等。
(3) 異常監(jiān)控
產(chǎn)品的前端代碼在執(zhí)行過程中也會(huì)發(fā)生異常,因此需要引入異常監(jiān)控。及時(shí)的上報(bào)異常情況,可以避免線上故障的發(fā)上。雖然大部分異常可以通過try catch的方式捕獲,但是比如內(nèi)存泄漏以及其他偶現(xiàn)的異常難以捕獲;
愛番番目前采用sentry進(jìn)行錯(cuò)誤日志采集。
4.2.3 監(jiān)控什么內(nèi)容
1.web
|
類別
|
內(nèi)容
|
|
頁面分析
|
具體豐富的頁面指標(biāo),提供如服務(wù)器端響應(yīng)時(shí)間、網(wǎng)絡(luò)延時(shí)、DOM解析和頁面渲染時(shí)間等性能指標(biāo)
幫助研發(fā)更快捷的定位服務(wù)端、客戶端的頁面問題
|
|
Ajax請(qǐng)求
|
獲取用戶訪問過程,頁面發(fā)出的所有Ajax請(qǐng)求URL、引用頁面URL,監(jiān)控某一Ajax請(qǐng)求的響應(yīng)時(shí)間、回調(diào)時(shí)間、上傳數(shù)據(jù)量、下載數(shù)據(jù)量以及響應(yīng)過程中服務(wù)器返回的錯(cuò)誤
|
|
JS error
|
代碼級(jí)定位出錯(cuò)頁面或者腳本URL,引用頁面URL,出錯(cuò)的行列信息、堆棧等信息,通過sourceMap定位源碼文件,通過pageId,operateId以及tid最大限度還原上下文
監(jiān)測(cè)Web App中JS錯(cuò)誤的數(shù)量,各瀏覽器出錯(cuò)百分比和JS錯(cuò)誤率隨時(shí)間變化的趨勢(shì)
|
|
瀏覽器監(jiān)測(cè)
|
統(tǒng)計(jì)不同版本瀏覽器和瀏覽器類型的平均頁面加載時(shí)間和吞吐率
提供基于多平臺(tái)瀏覽器性能分析,兼容性分析
|
|
慢頁面追蹤
|
抓取加載時(shí)間超過設(shè)定閾值的頁面上的元素信息,及每個(gè)元素的TCP建連、首包及剩余包等所需時(shí)間
詳細(xì)定位頁面上的哪些元素的加載拖慢了頁面的響應(yīng),為優(yōu)化用戶體驗(yàn)提供依據(jù)
|
2.其他端:
h5(瀏覽器、webview)
統(tǒng)計(jì)從端點(diǎn)擊開始,到指定頁面渲染全流程時(shí)間分布,包括(容器耗時(shí),框架耗時(shí),網(wǎng)絡(luò)耗時(shí),渲染耗時(shí)等)。
統(tǒng)計(jì)NPJS框架自身穩(wěn)定性,以及各個(gè)階段耗時(shí)。
統(tǒng)計(jì)任意多個(gè)操作各個(gè)時(shí)間斷耗時(shí)。
現(xiàn)在使用百度移動(dòng)端性能中臺(tái),功能基本滿足愛番番監(jiān)控、報(bào)警功能;
移動(dòng)端監(jiān)控指標(biāo)主要為 卡頓和崩潰,目前有崩潰堆棧信息日志;暫無交互時(shí)長分析(xray平臺(tái)有,手百性能中臺(tái)沒有)
electron監(jiān)控方案參考WEB版
四、方案調(diào)研
自建or接入其他平臺(tái)?
業(yè)務(wù)埋點(diǎn)采買神策。
性能監(jiān)控平臺(tái):
廠內(nèi):
性能中臺(tái) http://performance.baidu.com/
日志中臺(tái) http://app.baidu-int.com/
目前日志中臺(tái)可以接入日志,但是需求是前端頁面的性能指標(biāo),屬于性能平臺(tái)范圍,目前性能平臺(tái)無前端性能指標(biāo)建設(shè)。
性能中臺(tái)的定位主要是針對(duì)native,當(dāng)前通用能力主要是崩潰、卡頓、端異常、Flutter異常、日志回?fù)频龋渌囊恍┠芰χ饕谑职佟⒒蛘呦嚓P(guān)SDK上,還未對(duì)外輸出。經(jīng)溝通暫不考慮支持前端性能監(jiān)控。
廠外:性能監(jiān)控主流收費(fèi)平臺(tái):
-
監(jiān)控寶 https://www.jiankongbao.com/
收費(fèi)平臺(tái)功能大同小異,均能滿足前端基礎(chǔ)性能監(jiān)控需求。
優(yōu)點(diǎn):有較為成熟的解決方案,能快速滿足多端性能監(jiān)控基本需求;
缺點(diǎn):
-
收費(fèi)
-
無法與部門現(xiàn)有后端APM體系打通
-
無法滿足特定case分析需求
結(jié)論:復(fù)用神策埋點(diǎn)SDK存儲(chǔ),上報(bào)能力及通路,進(jìn)行SDK二次封裝;自建日志服務(wù)及展示系統(tǒng)。
五、方案設(shè)計(jì) (web)
1、采集
(1)埋點(diǎn)SDK
基于神策SDK進(jìn)行二次封裝
統(tǒng)一封裝埋點(diǎn)SDK,通過npm包形式進(jìn)行版本管理;使用方在公共模塊對(duì)埋點(diǎn)SDK進(jìn)行初始化。
增加無侵入性能采集能力,提供采樣率配置等可配置擴(kuò)展能力。
參考接口文檔
(2)通用統(tǒng)計(jì)指標(biāo)(參考聽云)
|
指標(biāo)
|
統(tǒng)計(jì)方式
|
白屏 |
用戶瀏覽器輸入網(wǎng)址后至瀏覽器出現(xiàn)文字或1px圖片所花費(fèi)時(shí)間。計(jì)算規(guī)則:優(yōu)先使用Chrome、IE提供的firstPaintTime,沒有獲取到計(jì)算head中l(wèi)ink、script腳本下載的最長時(shí)間。
|
首屏 |
用戶瀏覽器首屏內(nèi)所有的元素呈現(xiàn)所花費(fèi)時(shí)間。計(jì)算規(guī)則:尋找首屏區(qū)域內(nèi)的所有圖片,計(jì)算最長加載時(shí)間得到首屏?xí)r間。
|
可交互 |
功能可以使用的時(shí)間,也指domready時(shí)間。計(jì)算公式:可交互=Navigation Timing API domContentLoadedEventStart – fetchStart。
|
完全加載 |
頁面完全加載總時(shí)間。指從NavigationStart事件開始到LoadEventEnd事件結(jié)束,計(jì)算公式:LoadEventEnd-NavigationStart
|
HTML加載 |
指主HTML文件從DNS解析到加載完且不包含排隊(duì)時(shí)間和應(yīng)用服務(wù)器響應(yīng)時(shí)間,即包含DNS,TCP建連,Request和Response,計(jì)算公式:responseEnd-domainlookupStart-排隊(duì)時(shí)間-應(yīng)用服務(wù)器響應(yīng)時(shí)間
|
頁面渲染 |
指從responseEnd事件開始到loadEventEnd結(jié)束,包含DOM解析和資源加載,計(jì)算公式:LoadEventEnd-responseEnd
|
DOM解析 |
指從responseEnd事件開始到DomContentLoadedEventEnd事件結(jié)束,計(jì)算公式:DomContentLoadedEventEnd-responseEnd
|
資源加載 |
指從DomContentLoadedEventEnd事件開始到loadEventEnd事件結(jié)束,計(jì)算公式:loadEventEnd-DomContentLoadedEventEnd
|
JS錯(cuò)誤率 |
出現(xiàn)JS錯(cuò)誤的比例。JS錯(cuò)誤包含Javascript錯(cuò)誤代碼和位置信息。
|
服務(wù)端響應(yīng)時(shí)間 |
服務(wù)器響應(yīng)時(shí)間是指應(yīng)用服務(wù)器處理請(qǐng)求所消耗的時(shí)間,即應(yīng)用響應(yīng)時(shí)間,等于請(qǐng)求到達(dá)應(yīng)用服務(wù)器到應(yīng)用代碼執(zhí)行完成并輸出響應(yīng)信息的時(shí)間。(需要通過Server探針自動(dòng)注入方式嵌碼,否則服務(wù)器響應(yīng)時(shí)間為零)
|
AJAX請(qǐng)求響應(yīng)時(shí)間 |
所有Ajax請(qǐng)求時(shí)間在時(shí)間軸的投影合并的總耗時(shí)
|
unload |
卸載當(dāng)前頁面的耗時(shí),計(jì)算公式:unloadEnd-unloadStart
|
Redirect |
頁面重定向操作所消耗的時(shí)間,計(jì)算公式:redirectEnd-redirectStart
|
Cache |
取緩存數(shù)據(jù)的耗時(shí),計(jì)算公式:domainLookupStart-fetchStart
|
DNS |
通過域名解析服務(wù)(DNS),將指定的域名解析成IP地址的消耗時(shí)間。
|
TCP建連時(shí)間 |
瀏覽器和WEB服務(wù)器建立TCP/IP連接的消耗時(shí)間。當(dāng)元素下載完成后,瀏覽器可能會(huì)根據(jù)服務(wù)器返回的結(jié)果保持此連接,而不是完全關(guān)閉此連接。當(dāng)監(jiān)測(cè)節(jié)點(diǎn)再次和相同的服務(wù)器建立連接時(shí),會(huì)復(fù)用此連接,對(duì)應(yīng)消耗時(shí)間可能為0。此指標(biāo)即為TCP/IP連接三次握手的前二次握手的時(shí)間(從IE發(fā)送TCP包SYN到收到服務(wù)器返回的TCP包SYN ACK的時(shí)間),第三次握手時(shí)間(從IE發(fā)送TCP包ACK到服務(wù)器接收此TCP包的時(shí)間)不計(jì)算在內(nèi)。
|
排隊(duì)時(shí)間 |
排隊(duì)時(shí)間指服務(wù)器端的請(qǐng)求阻塞時(shí)間,即請(qǐng)求從Web前端服務(wù)器(例如Apache, nginx或F5負(fù)載均衡設(shè)備)到達(dá)應(yīng)用服務(wù)端的時(shí)間。
|
首包時(shí)間 |
從開始頁面請(qǐng)求到瀏覽器開始接收到HTML代碼的時(shí)間,不包括排隊(duì)時(shí)間和服務(wù)器端的時(shí)間,計(jì)算公式:responseStart-connectEnd -排隊(duì)時(shí)間-服務(wù)器響應(yīng)時(shí)間
|
剩余包時(shí)間 |
從responseStart事件開始到responseEnd事件結(jié)束,計(jì)算公式:responseEnd-responseStart
|
首次渲染時(shí)間 |
從導(dǎo)航到頁面首次渲染消耗的時(shí)間,計(jì)算公式:firstPaintTime-navigationStart(又名:白屏?xí)r間,firstPaintTime)
|
首次交互時(shí)間 |
從用戶的第一個(gè)動(dòng)作發(fā)生時(shí)間 – navigationStart,其中動(dòng)作包括:點(diǎn)擊,按鍵,滾動(dòng)鼠標(biāo)。
|
自定義加載時(shí)間(用戶可感知時(shí)間)
|
每個(gè)頁面都可以設(shè)置一個(gè)用戶自定義的加載時(shí)間性能指標(biāo)。計(jì)算方式為路由切換時(shí)間至主動(dòng)調(diào)用sdk ready方法時(shí)間差值
|
AJAX平響時(shí)間 |
平均每次AJAX請(qǐng)求的響應(yīng)時(shí)間
|
AJAX傳輸數(shù)據(jù)量 |
單位KB,平均每次AJAX請(qǐng)求的數(shù)據(jù)傳輸量(上傳+下載字節(jié)數(shù))
|
AJAX回調(diào)時(shí)間 |
平均每次AJAX請(qǐng)求的回調(diào)時(shí)間(回調(diào)時(shí)間是指當(dāng)數(shù)據(jù)從服務(wù)器傳到客戶端之后,本地代碼調(diào)用這些數(shù)據(jù)做相應(yīng)的處理,可以理解為本地執(zhí)行時(shí)間)
|
客戶端時(shí)間 |
從請(qǐng)求某資源到下載完過程中,沒有出現(xiàn)網(wǎng)絡(luò)傳輸?shù)臅r(shí)間片段之和,比如DNS-TCP建連,之間的切換需要消耗CPU來調(diào)度,這就可能會(huì)產(chǎn)生很短的時(shí)間空隙
|
事件平均響應(yīng)時(shí)間 |
操作請(qǐng)求完成時(shí)間。
|
統(tǒng)計(jì)方式,通過performance API
Core Web Vitals(https://web.dev/vitals/)
核心指標(biāo)
|
metrics
|
描述
|
含義
|
|
TTFB
|
time to first byte
|
從請(qǐng)求到數(shù)據(jù)返回第一個(gè)字節(jié)所消耗時(shí)間
|
|
TTI
|
DOM樹構(gòu)建完畢,可綁定事件
|
|
|
DCL
|
DOMContentLoaded
|
HTML文檔完全加載解析完成
|
|
L
|
onLoad
|
依賴資源全部加載完畢
|
|
FP
|
first paint
|
第一個(gè)像素點(diǎn)繪制完成時(shí)間
|
|
FCP
|
首次繪制非空白節(jié)點(diǎn)時(shí)間
|
|
|
FMP
|
first meaningful paint
|
首次有意義繪制(需要自定義)
|
|
LCP
|
在視口中最大的頁面元素加載時(shí)間
|
|
|
FID
|
用戶首次和頁面交互到頁面響應(yīng)的時(shí)間
|
|
|
CLS
|
度量在頁面開始加載到其生命周期狀態(tài)更改為隱藏之間發(fā)生的所有意外布局更改的累積分?jǐn)?shù)
|
使用谷歌Web Vitals進(jìn)行獲取
interface Metric {
// The name of the metric (in acronym form).
name: 'CLS' | 'FCP' | 'FID' | 'LCP' | 'TTFB';
// The current value of the metric.
value: number;
// The delta between the current value and the last-reported value.
// On the first report, `delta` and `value` will always be the same.
delta: number;
// A unique ID representing this particular metric that's specific to the
// current page. This ID can be used by an analytics tool to dedupe
// multiple values sent for the same metric, or to group multiple deltas
// together and calculate a total.
id: string;
// Any performance entries used in the metric value calculation.
// Note, entries will be added to the array as the value changes.
entries: (PerformanceEntry | FirstInputPolyfillEntry | NavigationTimingPolyfillEntry)[];
}
(3)前后端調(diào)用打通
-
pageGuid,重新定義pageGuid生成規(guī)則,暫定為 router+orgId+timestamp+random ? 進(jìn)行加密處理
-
requestId,由網(wǎng)絡(luò)庫統(tǒng)一生成,生成方式參考BFE_logId生成規(guī)則,在請(qǐng)求header中攜帶,用于skywalking tid進(jìn)行映射
-
operateId,需要使用者明確【操作】起止時(shí)機(jī),并手動(dòng)調(diào)用SKD API。
1) 在使用方初始化【操作】時(shí),調(diào)用 SDK.initOpt('操作名'),該方法返回本次操作operateName,用于后續(xù)傳遞;
1) 在使用方明確【操作】開始時(shí),調(diào)用SDK.startOpt('operateName'),SDK生成唯一operateId,存于localStorage.pageGuid..operateName.operateId(示例);
2) 為了保證上下文獨(dú)立性,在該操作涉及到的請(qǐng)求options中配置{operateName: 'operateName'},網(wǎng)絡(luò)庫在發(fā)送請(qǐng)求時(shí),主動(dòng)獲取operateId并攜帶,取值方式為:localStorage.pageGuid..operateName.operateId || ‘’;
3) 在使用方明確【操作】結(jié)束時(shí),需調(diào)用SDK.endOperate(操作名);SDK將進(jìn)行該次操作相關(guān)操作時(shí)間,頁面渲染時(shí)長等統(tǒng)計(jì),存儲(chǔ)在localStorage.pageGuid.bucket中,通過上報(bào)策略時(shí)機(jī)進(jìn)行統(tǒng)一上報(bào)。

現(xiàn)有sentry在采集錯(cuò)誤日志時(shí),增加pageGuid,requestId,operateId相關(guān)信息,通過(3)映射方式與Skywalking 調(diào)用鏈進(jìn)行鏈路打通。
鑒別有用報(bào)錯(cuò)信息分類,確定報(bào)警閾值及報(bào)警人配置,進(jìn)行HI,郵件,短信,電話報(bào)警方式;增加報(bào)警升級(jí)策略。
增強(qiáng)報(bào)表展示能力,通過pageGuid等維度查看頁面級(jí)別報(bào)錯(cuò),以便于進(jìn)行下一步排查和跟進(jìn)。
2、上報(bào)
直接復(fù)用神策SDK上報(bào)機(jī)制。
1.上報(bào)時(shí)機(jī)(備選)
-
頁面加載和重新刷新 -
頁面切換路由
-
存儲(chǔ)于localStorage.pageGuid.bucket中; -
bucket中數(shù)量超過閾值,觸發(fā)上報(bào); -
頁面卸載unload,觸發(fā)上報(bào);
2.上報(bào)方式
如何上報(bào)性能數(shù)據(jù),我們第一反應(yīng)就是通過ajax請(qǐng)求的形式來上報(bào)前端性能數(shù)據(jù)。這種方法有一些缺陷,比如必須對(duì)跨域做特殊處理以及如果頁面銷毀后,相應(yīng)的ajax方法并不一定發(fā)送成功等問題。
其中跨域的問題比較好處理,最難解決的問題是 如果頁面銷毀,那么對(duì)應(yīng)的ajax方法并不一定能成功發(fā)送。
? 根據(jù)google analytics(GA)中的方法,根據(jù)瀏覽器的兼容性以及url的長度,來采用不同的方法上報(bào)性能數(shù)據(jù):
通過動(dòng)態(tài)創(chuàng)建img標(biāo)簽的方式,在img.src中拼接url的方式發(fā)送請(qǐng)求,不存在跨域限制。如果url太長,則才用sendBeacon的方式發(fā)送請(qǐng)求,如果sendBeacon方法不兼容,則發(fā)送ajax post同步請(qǐng)求。
(1)、sendBeacon方法
??解決在文檔卸載或者頁面關(guān)閉后無法完成異步ajax請(qǐng)求的問題,很多情況下我們會(huì)把異步變成同步。在頁面卸載的unload或者beforeunload事件中執(zhí)行同步方法調(diào)用。
但是同步方法調(diào)用存在一個(gè)問題,就是會(huì)推遲A頁面切換進(jìn)入B頁面的時(shí)間。而sendBeacon方法解決了該問題,簡(jiǎn)單來說:
sendBeacon方法在頁面銷毀期,可以異步的發(fā)送數(shù)據(jù),因此不會(huì)造成類似同步ajax請(qǐng)求那樣的阻塞問題,也不會(huì)影響下一個(gè)頁面的渲染
sendBeacon的調(diào)用方式為:
function sendBeacon(url,data){ //判斷支不支持navigator.sendBeacon let headers = { type: 'application/x-www-form-urlencoded' }; let blob = new Blob([JSON.stringify(data)], headers); navigator.sendBeacon(url,blob); }
(2)動(dòng)態(tài)創(chuàng)建img標(biāo)簽的形式
??通過動(dòng)態(tài)創(chuàng)建img標(biāo)簽的形式,指定src屬性所指定的url來發(fā)送請(qǐng)求,首先不受跨域的限制,其次img標(biāo)簽動(dòng)態(tài)插入,會(huì)延遲頁面的卸載保證圖片的插入,因此可以保證在頁面的銷毀期,請(qǐng)求可以發(fā)生。
function imgReport(url, data) { if (!url || !data) { return; } let image = document.createElement('img'); let items = []; items = JSON.Parse(data); let name = 'img_' + (+new Date()); image.onload = image.onerror = function () { }; let newUrl = url + (url.indexOf('?') < 0 ? '?' : '&') + items.join('&'); image.src = newUrl; }
(3)同步ajax post請(qǐng)求
??動(dòng)態(tài)創(chuàng)建img標(biāo)簽的方法,拼接url的時(shí)候存在一定的問題,因?yàn)闉g覽器對(duì)url的長度是有限制的。而sendBeacon方法兼容性不是很好,最后兜底的處理方式就是發(fā)送同步的ajax請(qǐng)求,同步的ajax請(qǐng)求前面說過,會(huì)在頁面銷毀期之前執(zhí)行,雖然會(huì)有一定程度的阻塞下一個(gè)頁面的渲染。
function xmlLoadData(url,data) {
var client = new XMLHttpRequest();
client.open("POST", url,false);
client.setRequestHeader("Content-Type", "application/json; charset=utf-8");
client.send(JSON.stringify(data));
}
(4)綜合解決方案
??首先拼接攜帶參數(shù)的完整的url,判斷url的長度,如果url的長度小于瀏覽器允許的最大長度內(nèi),那么通過動(dòng)態(tài)創(chuàng)建img標(biāo)簽的形式來發(fā)送前端性能數(shù)據(jù),如果url太長,則判斷瀏覽器是否支持sendBeacon方法,如果支持,則通過sendBeacon方法來發(fā)送請(qǐng)求,否則發(fā)送同步的ajax請(qǐng)求。
function dealWithUrl(url,appId){ let times = performanceInfo(appId); let items = decoupling(times); let urlLength = (url + (url.indexOf('?') < 0 ? '?' : '&') + items.join('&')).length; if(urlLength<2083){ imgReport(url,times); }else if(navigator.sendBeacon){ sendBeacon(url,times); }else{ xmlLoadData(url,times); } }
3、方案設(shè)計(jì)(Hybrid H5)
3.1總體架構(gòu)
3.2.上報(bào)流程

3.3.流程時(shí)序圖

4.服務(wù)端采集及分析
搭建OAP服務(wù),進(jìn)行數(shù)據(jù)清洗加工及展示

少壯不努力,長大像毛利~

浙公網(wǎng)安備 33010602011771號(hào)