當前位置: 妍妍網 > 碼農

分享3種常用的前端埋點方式

2024-01-29碼農

前言


大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎是進階的前提是我的初心~

只有了解使用者,我們才能服務好使用者,而最接近使用者的我們,自然要承擔起更多的責任。

那麽在一個企業中,我們要如何去了解使用者呢?
最直接有效的方式就是了解使用者的行為,了解使用者在網站中做了什麽,呆了多久。
而如何去實作這一操作,這就涉及到我們前端的埋點了。

埋點方式

在聊如何進行埋點前,我們先介紹下什麽是埋點?

所謂'埋點'是數據采集領域(尤其是使用者行為數據采集領域)的術語,指的是針對特定使用者行為或事件進行捕獲、處理和發送的相關技術及其實施過程。. 比如使用者某個icon點選次數、觀看某個視訊的時長等等。

我們可以知道埋點是實際上是對特定事件或者行為的數據監控和上報, 常見的埋點上報方式有ajax,img,navigator.sendBeacon下面介紹下這三種埋點上報方式

基於ajax的埋點上報

介紹

因為埋點實際上是對關鍵節點的數據進行上報是和伺服端互動的一個過程,所以我們可以和後端約定一個介面透過ajax去進行數據上報。

程式碼實作

我們可以封裝一個方法,程式碼如下:

functionburyingPointAjax(data{
returnnewPromise((resolve, reject) => {
// 建立ajax請求
const xhr = new XMLHttpRequest();
// 定義請求介面
xhr.open("post"'/buryingPoint'true);
// 發送數據
xhr.send(data);
});
}

使用時,直接呼叫即可

let info = {}
buryingPointAjax(info) // 這樣就成功上報了info的物件

缺點

一般而言,埋點網域名稱並不是當前網域名稱,因此請求會存在跨域風險,且如果ajax配置不正確可能會瀏覽器攔截。因此使用ajax這類請求並不是萬全之策。

基於img的埋點上報

上面可以看到如果使用ajax的話,會存在跨域的問題。而且數據上報前端主要是負責將數據傳遞到後端,並不過分強調前後端互動。

因此我們可以透過一些支持跨域的標簽去實作數據上報功能。

script,link,img就是我們上報的數據的最好物件

先說結論,這裏推薦使用img標簽去實作。

script及link的缺陷

因為埋點涉及到請求,因此 我們需要保證script和link標簽的src可以正常請求
如果需要請求script和link,我們需要將標簽掛載到頁面上。

驗證缺陷

不妨驗證下,我們在管理台中加入以下程式碼:

let a = document.createElement('script')
a.src = 'https://lf-headquarters-speed.yhgfb-cn-static.com/obj/rc-client-security/web/stable/1.0.0.28/bdms.js'

建立一個script標簽,未掛載中頁面上,並不會發起請求

書接上文,當我們將這個標簽掛載中頁面上時:

document.body.appendChild(a)

這時發起了請求

結論

當我們使用script和link進行埋點上報時,需要掛載到頁面上,而反復操作dom會造成頁面效能受影響,而且載入js/css資源還會阻塞頁面渲染,影響使用者體驗 ,因此對於需要頻繁上報的埋點而言,script和link並不合適。

基於img做埋點上報

通常使用img標簽去做埋點上報, img標簽載入並不需要掛載到頁面上,基於js去new image(),設定其src之後就可以直接請求圖片。

驗證img優勢

控制台去建立一個image標簽,如下:

var img=new Image();
img.src="https://lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web/img/MaskGroup.13dfc4f1.png";

可以看到即便未被掛載到頁面上依舊發起了請求。

結論

因此當我們做埋點上報時,使用img是一個不錯的選擇。

  1. img相容性好

  2. 無需掛載到頁面上,反復操作dom

  3. img的載入不會阻塞html的解析,但img載入後並不渲染,它需要等待Render Tree生成完後才和Render Tree一起渲染出來

註:通常埋點上報會使用gif圖, 合法的 GIF 只需要 43 個字節

基於Navigator.sendBeacon的埋點上報

Navigator.sendBeacon是目前通用的埋點上報方案, Navigator.sendBeacon方法接受兩個參數,第一個參數是目標伺服器的 URL,第二個參數是所要發送的數據(可選),可以是任意型別(字串、表單物件、二進制物件等等)。

介紹

navigator.sendBeacon() 方法可用於透過 HTTP POST [1] 將少量數據 異步 [2] 傳輸到 Web 伺服器。

作用

它主要用於將統計數據發送到 Web 伺服器,同時避免了用傳統技術(如: XMLHttpRequest [3] )發送分析數據的一些問題。

補充

sendBeacon 如果成功進入瀏覽器的發送佇列後,會返回true;如果受到佇列總數、數據大小的限制後,會返回false。返回ture後,只是表示進入了發送佇列,瀏覽器會盡力保證發送成功,但是否成功了,不會再有任何返回值。

例子

以金塊為例:

這裏發了一個post請求,將小量的數據發到伺服端,用於統計數據

優勢

相較於img標簽,使用navigator.sendBeacon會更規範,數據傳輸上可傳輸資源型別會更多。

對於ajax在頁面解除安裝時上報,ajax有可能沒上報完,頁面就解除安裝了導致請求中斷,因此ajax處理這種情況時必須作為同步操作.

sendBeacon是異步的,不會影響當前頁到下一個頁面的跳轉速度,且不受同域限制。這個方法還是異步發出請求,但是請求與當前頁面脫離關聯,作為瀏覽器的任務,因此可以保證會把數據發出去,不拖延解除安裝流程。

總結

前端埋點上報常使用ajax,img,navigator.sendBeacon。

不推薦使用ajax。

如果考慮相容性的話,img是不二之選。

目前最合適的方案是navigator.sendBeacon,不僅是異步的,而且不受同域限制,而且作為瀏覽器的任務,因此可以保證會把數據發出去,不影響頁面解除安裝。

常見埋點行為

點選觸發埋點

繫結點選事件,當點選目標元素時,觸發埋點上報。

functionclickButton(url, data{
navigator.sendBeacon(url, data)
}

頁面停留時間上報埋點

路由檔中,初始化一個startTime,當頁面離開時透過路由守衛計算停留時間。

let url = ''// 上報地址
let startTime = Date.now()
let currentTime = ''
router.beforeEach((to, from, next) => { 
if (to) {
currentTime = Date.now()
stayTime = parseInt(currentTime - startTime)
navigator.sendBeacon(url, {time: stayTime})
startTime = Date.now()
}
 })

錯誤監聽埋點

透過監聽函式去接收錯誤資訊。

vue錯誤捕獲

app.config.errorHandler = (err) => { 
navigator.sendBeacon(url, {error: error.message, text'vue執行異常' })
}

JS異常與靜態資源載入異常

window.addEventListener('error', (error) => { 
if (error.message) { 
navigator.sendBeacon(url, {error: error.message, text'js執行異常' })
else { 
navigator.sendBeacon(url, {error: error.filename, text'資源載入異常' })

}, true)

請求錯誤捕獲

axios.interceptors.response.use(
(response) => {
if (response.code == 200) {
returnPromise.resolve(response);
else {
returnPromise.reject(response);
}
},
(error) => {
// 返回錯誤邏輯
navigator.sendBeacon(url, {error: error, text'請求錯誤異常' })
}
);

內容可見埋點

透過交叉觀察器去監聽當前元素是否出現在頁面

// 可見性發生變化後的回呼 
functioncallback(data
navigator.sendBeacon(url, { target: data[0].target, text'內容可見' }) 

// 交叉觀察器配置項 
let options = {}; 
// 生成交叉觀察器 
const observer = new InterpObserver(callback); 
// 獲取目標節點 
let target = document.getElementById("target"); 
// 監聽目標元素 
observer.observe(target);

參考資料

[1]

HTTP POST: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/POST

[2]

異步: https://developer.mozilla.org/zh-CN/docs/Glossary/Asynchronous

[3]

XMLHttpRequest: https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest

作者:彩虹修狗

https://juejin.cn/post/7224132741997281338

結語

我是林三心

  • 一個待過 小型toG型外包公司、大型外包公司、小公司、潛力型創業公司、大公司 的作死型前端選手;

  • 一個偏前端的全幹工程師;

  • 一個不正經的金塊作者;

  • 逗比的B站up主;

  • 不帥的小紅書博主;

  • 喜歡打鐵的籃球菜鳥;

  • 喜歡歷史的乏味少年;

  • 喜歡rap的五音不全弱雞如果你想一起學習前端,一起摸魚,一起研究簡歷最佳化,一起研究面試進步,一起交流歷史音樂籃球rap,可以來俺的摸魚學習群哈哈,點這個,有7000多名前端小夥伴在等著一起學習哦 -->

  • 廣州的兄弟可以約飯哦,或者約球~我負責打鐵,你負責進球,謝謝~