為什么大廠前端監(jiān)控都在用GIF做埋點(diǎn)?
?什么是前端監(jiān)控?
它指的是通過一定的手段來獲取用戶行為以及跟蹤產(chǎn)品在用戶端的使用情況,并以監(jiān)控?cái)?shù)據(jù)為基礎(chǔ),為產(chǎn)品優(yōu)化指明方向,為用戶提供更加精確、完善的服務(wù)。
?
大廠技術(shù)??高級(jí)前端??Node進(jìn)階
點(diǎn)擊上方?程序員成長(zhǎng)指北,關(guān)注公眾號(hào)
回復(fù)1,加入高級(jí)Node交流群
前端監(jiān)控
一般來講一個(gè)成熟的產(chǎn)品,運(yùn)營(yíng)與產(chǎn)品團(tuán)隊(duì)需要關(guān)注用戶在產(chǎn)品內(nèi)的行為記錄,通過用戶的行為記錄來優(yōu)化產(chǎn)品,研發(fā)與測(cè)試團(tuán)隊(duì)則需要關(guān)注產(chǎn)品的性能以及異常,確保產(chǎn)品的性能體驗(yàn)以及安全迭代。
「所以前端監(jiān)控一般也分為三大類:」
數(shù)據(jù)監(jiān)控(監(jiān)控用戶行為)
PV/UV: PV(page view):即頁面瀏覽量或點(diǎn)擊量;UV(unique visitor):指訪問某個(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ì)停留較長(zhǎng)的頁面,增加廣告推送等等。
性能監(jiān)控(監(jiān)控頁面性能)
不同用戶,不同機(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)化前端性能,盡可能的提高用戶體驗(yàn)。
異常監(jiān)控(監(jiān)控產(chǎn)品、系統(tǒng)異常)
及時(shí)的上報(bào)異常情況,可以避免線上故障的發(fā)上。雖然大部分異??梢酝ㄟ^ try catch 的方式捕獲,但是比如內(nèi)存泄漏以及其他偶現(xiàn)的異常難以捕獲。常見的需要監(jiān)控的異常包括:
Javascript 的異常監(jiān)控 樣式丟失的異常監(jiān)控
埋點(diǎn)上報(bào)
OK,上面我們說到了前端監(jiān)控的三個(gè)分類,了解了一個(gè)產(chǎn)品需要監(jiān)控哪些內(nèi)容以及為什么需要監(jiān)控這些內(nèi)容,那么我們應(yīng)該怎么實(shí)現(xiàn)前端監(jiān)控呢?
實(shí)現(xiàn)前端監(jiān)控,第一步肯定是將我們要監(jiān)控的事項(xiàng)(數(shù)據(jù))給收集起來,再提交給后臺(tái)進(jìn)行入庫,最后再給數(shù)據(jù)分析組進(jìn)行數(shù)據(jù)分析,最后處理好的數(shù)據(jù)再同步給運(yùn)營(yíng)或者是產(chǎn)品。數(shù)據(jù)收集的豐富性和準(zhǔn)確性會(huì)直接影響到我們做前端監(jiān)控的質(zhì)量,因?yàn)槲覀儠?huì)以此為基礎(chǔ),為產(chǎn)品的未來發(fā)展指引方向。
現(xiàn)在常見的埋點(diǎn)上報(bào)方法有三種:手動(dòng)埋點(diǎn)、可視化埋點(diǎn)、無埋點(diǎn)
手動(dòng)埋點(diǎn)
手動(dòng)埋點(diǎn),也叫代碼埋點(diǎn),即純手動(dòng)寫代碼,調(diào)用埋點(diǎn) SDK 的函數(shù),在需要埋點(diǎn)的業(yè)務(wù)邏輯功能位置調(diào)用接口,上報(bào)埋點(diǎn)數(shù)據(jù),像[友盟]、[百度統(tǒng)計(jì)]等第三方數(shù)據(jù)統(tǒng)計(jì)服務(wù)商大都采用這種方案。手動(dòng)埋點(diǎn)讓使用者可以方便地設(shè)置自定義屬性、自定義事件;所以當(dāng)你需要深入下鉆,并精細(xì)化自定義分析時(shí),比較適合使用手動(dòng)埋點(diǎn)。
手動(dòng)埋點(diǎn)的缺陷就是,項(xiàng)目工程量大,需要埋點(diǎn)的位置太多,而且需要產(chǎn)品開發(fā)運(yùn)營(yíng)之間相互反復(fù)溝通,容易出現(xiàn)手動(dòng)差錯(cuò),如果錯(cuò)誤,重新埋點(diǎn)的成本也很高。
可視化埋點(diǎn)
通過可視化交互的手段,代替上述的代碼埋點(diǎn)。將業(yè)務(wù)代碼和埋點(diǎn)代碼分離,提供一個(gè)可視化交互的頁面,輸入為業(yè)務(wù)代碼,通過這個(gè)可視化系統(tǒng),可以在業(yè)務(wù)代碼中自定義的增加埋點(diǎn)事件等等,最后輸出的代碼耦合了業(yè)務(wù)代碼和埋點(diǎn)代碼。
可視化埋點(diǎn)的缺陷就是可以埋點(diǎn)的控件有限,不能手動(dòng)定制。
無埋點(diǎn)
無埋點(diǎn)則是前端自動(dòng)采集全部事件,上報(bào)埋點(diǎn)數(shù)據(jù),由后端來過濾和計(jì)算出有用的數(shù)據(jù)。優(yōu)點(diǎn)是前端只要一次加載埋點(diǎn)腳本,缺點(diǎn)是流量和采集的數(shù)據(jù)過于龐大,服務(wù)器性能壓力山大。
為什么都用GIF來做埋點(diǎn)?
發(fā)現(xiàn)過程
首先說一下我是怎么發(fā)現(xiàn)的,前一段時(shí)間,產(chǎn)品提了個(gè)需求,說我們現(xiàn)在的書籍曝光上報(bào)規(guī)范并不是他們想要的數(shù)據(jù),并且以后所有頁面的書籍上報(bào)都統(tǒng)一成最新規(guī)范。
曝光規(guī)范:
書籍出現(xiàn)在可視區(qū)并停留1秒,算作有效曝光 書籍不能重復(fù)曝光,假如它一直在可視區(qū)滾動(dòng)時(shí)只能上報(bào)一次 當(dāng)它移出可視區(qū)后再回到可視區(qū),再按第一點(diǎn)進(jìn)行曝光
OK,既然要所有頁面統(tǒng)一,那就只能封裝成通用庫來使用了,這里實(shí)現(xiàn)邏輯就不貼了,想看的私聊我發(fā)你,主要的難點(diǎn)就是停留時(shí)長(zhǎng)計(jì)算,以及曝光標(biāo)記。
const?exposeReportClass?=?new?exposeReport({
??????scrollDom:?"",??//?滾動(dòng)容器,建議指定一個(gè)滾動(dòng)容器,不傳默認(rèn)為window
??????watchDom:?".bookitem",?//?監(jiān)聽的dom,建議使用class類,標(biāo)簽也支持
??????time:?1000?????????????//?停留有效時(shí)長(zhǎng)ms
});
//?提供兩個(gè)上報(bào)方法
exposeReportClass.didReport(()=>{
??//?手動(dòng)上報(bào)
??//callback
})
exposeReportClass.scrollReport(()=>{
??//?滾動(dòng)上報(bào)
??//callback
})
//?
具體業(yè)務(wù)邏輯之需要放在對(duì)應(yīng)的callback里面,而上報(bào)邏輯開發(fā)者無需考慮,因?yàn)槲业讓右呀?jīng)統(tǒng)一處理好了。
然后我再測(cè)試的時(shí)候就發(fā)現(xiàn),上報(bào)發(fā)的請(qǐng)求居然是通過圖片發(fā)起的,并不是我們認(rèn)為的接口上報(bào)。

然后我去查了下資料,發(fā)現(xiàn)很多大廠的上報(bào)都是這么干的!
使用GIF上報(bào)的原因
向服務(wù)器端上報(bào)數(shù)據(jù),可以通過請(qǐng)求接口,請(qǐng)求普通文件,或者請(qǐng)求圖片資源的方式進(jìn)行。只要能上報(bào)數(shù)據(jù),無論是請(qǐng)求GIF文件還是請(qǐng)求其他普通文件(JS)或者是請(qǐng)求接口,服務(wù)器端其實(shí)并不關(guān)心具體的上報(bào)方式。那為什么所有系統(tǒng)都統(tǒng)一使用了請(qǐng)求GIF圖片的方式上報(bào)數(shù)據(jù)呢?
「防止跨域」
一般而言,打點(diǎn)域名都不是當(dāng)前域名,所以所有的接口請(qǐng)求都會(huì)構(gòu)成跨域。而跨域請(qǐng)求很容易出現(xiàn)由于配置不當(dāng)被瀏覽器攔截并報(bào)錯(cuò),這是不能接受的。但圖片的src屬性并不會(huì)跨域,并且同樣可以發(fā)起請(qǐng)求。(排除接口上報(bào))
「防止阻塞頁面加載,影響用戶體驗(yàn)」
通常,創(chuàng)建資源節(jié)點(diǎn)后只有將對(duì)象注入到瀏覽器DOM樹后,瀏覽器才會(huì)實(shí)際發(fā)送資源請(qǐng)求。反復(fù)操作DOM不僅會(huì)引發(fā)性能問題,而且載入js/css資源還會(huì)阻塞頁面渲染,影響用戶體驗(yàn)。
但是圖片請(qǐng)求例外。構(gòu)造圖片打點(diǎn)不僅不用插入DOM,只要在js中new出Image對(duì)象就能發(fā)起請(qǐng)求,而且還沒有阻塞問題,在沒有js的瀏覽器環(huán)境中也能通過img標(biāo)簽正常打點(diǎn),這是其他類型的資源請(qǐng)求所做不到的。(排除文件方式)
「相比PNG/JPG,GIF的體積最小」
最小的BMP文件需要74個(gè)字節(jié),PNG需要67個(gè)字節(jié),而合法的GIF,只需要43個(gè)字節(jié)。
同樣的響應(yīng),GIF可以比BMP節(jié)約41%的流量,比PNG節(jié)約35%的流量。
「并且大多采用的是1*1像素的透明GIF來上報(bào)」
1x1像素是最小的合法圖片。而且,因?yàn)槭峭ㄟ^圖片打點(diǎn),所以圖片最好是透明的,這樣一來不會(huì)影響頁面本身展示效果,二者表示圖片透明只要使用一個(gè)二進(jìn)制位標(biāo)記圖片是透明色即可,不用存儲(chǔ)色彩空間數(shù)據(jù),可以節(jié)約體積。
Node 社群
我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
如果你覺得這篇內(nèi)容對(duì)你有幫助,我想請(qǐng)你幫我2個(gè)小忙:
1. 點(diǎn)個(gè)「在看」,讓更多人也能看到這篇文章 2. 訂閱官方博客?www.inode.club?讓我們一起成長(zhǎng) 點(diǎn)贊和在看就是最大的支持??
