自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

前端埋點與監(jiān)控最佳實踐:從基礎(chǔ)到全流程實現(xiàn)

開發(fā) 前端
埋點主要用于收集用戶行為數(shù)據(jù)。在日常開發(fā)中,我們會通過 在前端代碼中插入代碼或腳本的方式 來實現(xiàn)埋點功能。埋點的主要作用就是:捕獲特定用戶行為(如點擊、瀏覽、提交表單、頁面跳轉(zhuǎn)等)以及關(guān)鍵業(yè)務數(shù)據(jù)(如下單金額、商品類別等)

大綱

我們會從以下三個方向來講解埋點與監(jiān)控的知識:

  • 什么是埋點?什么是監(jiān)控?
  • JS 中實現(xiàn)監(jiān)控的核心方案
  • 寫一個“相對”完整的監(jiān)控實例

一、什么是埋點?什么是監(jiān)控?

在日常溝通中,我們經(jīng)常會把【埋點】和【監(jiān)控】放到一起說,但是它們在本質(zhì)上是有一定的區(qū)別的:

1. 埋點

埋點主要用于收集用戶行為數(shù)據(jù)。在日常開發(fā)中,我們會通過 在前端代碼中插入代碼或腳本的方式 來實現(xiàn)埋點功能。

埋點的主要作用就是:捕獲特定用戶行為(如點擊、瀏覽、提交表單、頁面跳轉(zhuǎn)等)以及關(guān)鍵業(yè)務數(shù)據(jù)(如下單金額、商品類別等)

在日常開發(fā)中,埋點的實現(xiàn)方案大致可以分為以下三大類:

  • 手動埋點:在代碼中手動加入記錄代碼來捕獲特定事件。
  • 自動埋點:利用 DOM 事件代理等技術(shù)來捕獲頁面上所有事件,從而減少手動配置。
  • 可視化埋點:通過工具界面標記需要采集的元素和事件,可以不用手寫代碼。

2. 監(jiān)控

而監(jiān)控則主要關(guān)注 系統(tǒng)的性能和穩(wěn)定性。在日常開發(fā)中,我們會通過 采集頁面加載時間、資源請求、錯誤日志等數(shù)據(jù) 的方式來實現(xiàn)前端監(jiān)控。

監(jiān)控的主要作用就是:及時發(fā)現(xiàn)并定位頁面性能瓶頸或代碼異常,目的是為了保障系統(tǒng)不出 bug

在日常開發(fā)中,監(jiān)控一般需要完成以下三大部分:

  • 性能監(jiān)控:如:首屏加載時間、頁面交互耗時、資源加載耗時等。
  • 錯誤監(jiān)控:捕獲 JavaScript 錯誤、網(wǎng)絡(luò)請求失敗、資源加載異常等。
  • 用戶體驗監(jiān)控:收集白屏、卡頓等影響用戶體驗的問題等。

區(qū)別總結(jié)

維度

前端埋點

前端監(jiān)控

目標

捕獲用戶行為數(shù)據(jù)

監(jiān)控系統(tǒng)性能、錯誤、穩(wěn)定性

數(shù)據(jù)類型

用戶點擊、表單提交、頁面跳轉(zhuǎn)等

頁面加載時間、錯誤日志、卡頓情況等

實現(xiàn)方式

手動埋點、自動埋點、可視化埋點

錯誤捕獲、性能指標采集

核心關(guān)注點

用戶行為、業(yè)務數(shù)據(jù)

系統(tǒng)Bug、性能優(yōu)化

二、JS 中實現(xiàn)監(jiān)控的核心方案

根據(jù)上面所說,我們知道埋點和監(jiān)控的目的存在不同,但是它們的思路確是有很多一致性的,其核心都是:獲取關(guān)鍵的數(shù)據(jù),發(fā)送(上報)給服務端,依據(jù)數(shù)據(jù)來解決其不同的目的。

所以,無論是埋點也好,還是監(jiān)控也罷,我們都需要 獲取關(guān)鍵位置數(shù)據(jù)。

1. 跟蹤用戶事件(點擊、滾動等)

定義通用跟蹤函數(shù)(后續(xù)事件會通過該函數(shù)完成上報):trackEvent 函數(shù)接收事件類型和事件詳情,并上報到服務端。

// 用于記錄或發(fā)送跟蹤數(shù)據(jù)到服務器的函數(shù)
function trackEvent(eventType, details) {
    console.log(`Event: ${eventType}`, details); // 在控制臺打印事件類型和詳情
    // 上報到服務端。
    fetch('/測試接口地址', { method: 'POST', body: JSON.stringify({ eventType, details }) });
}

捕獲按鈕點擊事件:獲取 id 為 myButton 的按鈕,并在其 click 事件上添加監(jiān)聽器。在按鈕被點擊時調(diào)用 trackEvent 函數(shù),記錄點擊事件的類型(button_click)、按鈕 ID 和時間戳。

// 跟蹤按鈕點擊事件
const button = document.getElementById('myButton'); // 獲取按鈕元素
button.addEventListener('click', function () {
    trackEvent('button_click', { buttonId: 'myButton', timestamp: Date.now() }); // 記錄點擊事件并添加按鈕ID和時間戳
});

捕獲頁面滾動事件:在全局 scroll 事件上添加監(jiān)聽器,每當頁面發(fā)生滾動時調(diào)用 trackEvent 函數(shù),記錄滾動事件的類型(page_scroll)、頁面垂直滾動距離(scrollY)和時間戳。

// 跟蹤頁面滾動事件
window.addEventListener('scroll', function () {
    trackEvent('page_scroll', { scrollY: window.scrollY, timestamp: Date.now() }); // 記錄滾動事件并添加滾動位置和時間戳
});

2. 完成性能監(jiān)控指標

我們可以使用 PerformanceAPI,來檢測某些操作需要多長時間。如:頁面加載時間和 API 調(diào)用耗時的監(jiān)控:

頁面加載時間監(jiān)控:通過 window.addEventListener('load') 監(jiān)聽頁面加載完成的事件,在頁面完全加載后獲取當前時間(使用 performance.now()),計算出頁面加載的總耗時(從頁面初始化到加載完成的時間),并通過 trackEvent 函數(shù)將事件類型、耗時數(shù)據(jù)等記錄下來。

// 測量頁面加載時間
window.addEventListener('load', function () {
    const pageLoadTime = performance.now(); // 獲取頁面加載完成后的時間(毫秒)
    trackEvent('page_load', { duration: pageLoadTime }); // 記錄頁面加載事件,并包含加載耗時數(shù)據(jù)
});

API 調(diào)用耗時監(jiān)控:在 measureApiCallPerformance 函數(shù)中使用 performance.now() 獲取調(diào)用 API 前的開始時間,通過 fetch 方法發(fā)起網(wǎng)絡(luò)請求并在響應返回后再次獲取時間差,計算 API 請求的總耗時。將 API 耗時和接口地址等信息通過 trackEvent 函數(shù)記錄下來。

// 測量 API 調(diào)用的耗時
function measureApiCallPerformance() {
    const start = performance.now(); // 記錄 API 調(diào)用的開始時間

    fetch('https://api.sunday.com/data')
        .then(response => response.json())
        .then(data => {
            const duration = performance.now() - start; // 計算 API 調(diào)用的耗時
            trackEvent('api_call', { duration: duration, endpoint: 'https://api.sunday.com/data' }); // 記錄 API 調(diào)用事件,并包含耗時和接口地址
        });
}

3. 進行錯誤追蹤監(jiān)聽

我們可以利用 window.onerror 回調(diào)或者直接使用一些庫(如:Sentry)完成錯誤監(jiān)聽:

基礎(chǔ)錯誤跟蹤:通過 window.onerror 捕獲全局 JavaScript 錯誤。當錯誤發(fā)生時,window.onerror 會自動獲取錯誤的詳細信息(如錯誤信息、文件、行號、列號及堆棧信息),并將這些信息通過 trackEvent 函數(shù)發(fā)送到后臺,用于后續(xù)的錯誤分析和排查。

// 使用 window.onerror 實現(xiàn)基礎(chǔ)的錯誤跟蹤
window.onerror = function (message, source, lineno, colno, error) {
    // 捕獲 JavaScript 錯誤信息,并通過 trackEvent 函數(shù)記錄
    trackEvent('js_error', {
        message: message,      // 錯誤信息
        source: source,        // 錯誤發(fā)生的文件
        lineno: lineno,        // 錯誤所在的行號
        colno: colno,          // 錯誤所在的列號
        error: error ? error.stack : '' // 錯誤的堆棧信息(如果有)
    });
};

第三方錯誤跟蹤服務(Sentry):Sentry 是一個常用的錯誤監(jiān)控服務。通過 dsn 配置唯一的項目標識,之后可以使用 Sentry.captureException 方法捕獲并上報自定義錯誤。這種方式適合用于捕獲更多類型的異常并進行詳細的錯誤分析。

// 使用第三方服務 Sentry 進行錯誤跟蹤
Sentry.init({ dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0' }); // 初始化 Sentry
Sentry.captureException(new Error('在這里描述錯誤內(nèi)容')); // 捕獲并上報自定義錯誤

4. 自定義的埋點上報

有時候我們可能還需要進行一些特別要求的數(shù)據(jù)上報,比如:跟蹤用戶在頁面特定區(qū)域的停留時間,一共分成三步來做:

  1. 當用戶的鼠標進入指定區(qū)域(ID 為 sectionId)時,通過 mouseenter 事件記錄進入的時間戳 sectionStartTime。
  2. 當用戶的鼠標離開該區(qū)域時,通過 mouseleave 事件獲取當前時間,計算用戶在該區(qū)域的停留時長 timeSpent。
  3. 將停留時間和區(qū)域標識一起通過 trackEvent 函數(shù)發(fā)送到分析系統(tǒng),方便后續(xù)分析用戶在頁面不同區(qū)域的停留時長
// 跟蹤用戶在頁面特定區(qū)域的停留時間
let sectionStartTime = 0; // 記錄進入?yún)^(qū)域的時間
const sectionElement = document.getElementById('sectionId'); // 獲取目標區(qū)域的 DOM 元素

// 當用戶鼠標進入該區(qū)域時觸發(fā)
sectionElement.addEventListener('mouseenter', function () {
    sectionStartTime = Date.now(); // 記錄進入?yún)^(qū)域的時間戳
});

// 當用戶鼠標離開該區(qū)域時觸發(fā)
sectionElement.addEventListener('mouseleave', function () {
    const timeSpent = Date.now() - sectionStartTime; // 計算停留時間
    trackEvent('time_spent', { section: 'sectionId', duration: timeSpent }); // 上報停留時間和區(qū)域標識
});

5. 局部小總結(jié)

通過以上的幾個案例,我們可以再次明確:監(jiān)控核心就是獲取關(guān)鍵的數(shù)據(jù),發(fā)送(上報)給服務端

我們只需要 依照自己的需求,找到對應的 事件節(jié)點,獲取 需要上報的數(shù)據(jù),通過接口傳遞給服務端即可。


PS:這里需要注意的是 上報的方式分為:【統(tǒng)一上報】和 【實時上報】 兩大類,這里不去細說。

因此,想要完成監(jiān)控,那么就需要更加深入的了解關(guān)鍵事件節(jié)點,如:瀏覽器窗口事件、鼠標事件、鍵盤事件、表單事件 甚至是 DOM 是否可見

三、一個完整的表單監(jiān)控示例

那么接下來咱們就完成一個表單監(jiān)控示例。他可以監(jiān)控到 瀏覽量、按鈕點擊量和表單提交量 等

<!DOCTYPE html>
<html lang="en">
 <head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>表單行為跟蹤示例</title>
 </head>
 <body>
  <!-- 示例表單 -->
  <h1>用戶注冊表單</h1>
  <form id="registrationForm">
   <label for="username">用戶名:</label>
   <input type="text" id="username" name="username" required />
   <br /><br />

   <label for="email">郵箱:</label>
   <input type="email" id="email" name="email" required />
   <br /><br />

   <label for="password">密碼:</label>
   <input type="password" id="password" name="password" required />
   <br /><br />

   <button type="button" id="submitButton">注冊</button>
  </form>

  <script>
   // 通用跟蹤函數(shù):用于記錄事件并發(fā)送到服務器
   function trackEvent(eventType, details) {
    console.log(`Event: ${eventType}`, details)
    // 將數(shù)據(jù)發(fā)送到分析服務
    fetch('/請求路徑', {
     method: 'POST',
     headers: { 'Content-Type': 'application/json' },
     body: JSON.stringify({ eventType, details })
    })
   }

   // 1. 監(jiān)控頁面瀏覽量
   window.addEventListener('load', function () {
    trackEvent('page_view', {
     url: window.location.href,
     timestamp: Date.now()
    })
   })

   // 2. 監(jiān)控輸入字段聚焦事件
   const inputFields = document.querySelectorAll('#registrationForm input')
   inputFields.forEach((field) => {
    field.addEventListener('focus', function () {
     trackEvent('input_focus', {
      fieldName: field.name,
      timestamp: Date.now()
     })
    })
   })

   // 3. 監(jiān)控按鈕點擊量
   const submitButton = document.getElementById('submitButton')
   submitButton.addEventListener('click', function () {
    trackEvent('button_click', {
     buttonId: 'submitButton',
     timestamp: Date.now()
    })

    // 模擬提交表單,調(diào)用表單提交處理邏輯
    handleSubmit()
   })

   // 4. 監(jiān)控表單提交量
   const form = document.getElementById('registrationForm')
   function handleSubmit() {
    // 驗證表單是否有效(如果需要可以增加更多驗證邏輯)
    if (form.checkValidity()) {
     trackEvent('form_submit', {
      formId: 'registrationForm',
      formData: {
       username: form.username.value,
       email: form.email.value,
       password: form.password.value // 注意:實際場景中避免記錄敏感信息
      },
      timestamp: Date.now()
     })

     // 模擬發(fā)送表單數(shù)據(jù)到服務器
     fetch('/請求路徑', {
      method: 'POST',
      body: new FormData(form)
     })
      .then((response) => response.json())
      .then((data) => {
       console.log('Form submitted successfully', data)
      })
    } else {
     alert('請?zhí)顚懲暾韱?)
    }
   }
  </script>
 </body>
</html>

測試執(zhí)行結(jié)果如下:

圖片圖片

責任編輯:武曉燕 來源: 程序員Sunday
相關(guān)推薦

2023-12-13 18:46:50

FlutterAOP業(yè)務層

2024-08-27 08:27:19

2024-07-17 09:03:56

2025-02-08 07:00:00

2024-06-14 08:19:45

2024-01-11 11:25:22

2024-07-03 10:09:29

2023-01-10 09:08:53

埋點數(shù)據(jù)數(shù)據(jù)處理

2024-12-30 08:58:04

2018-11-14 11:26:49

神策數(shù)據(jù)

2021-02-05 09:00:00

開發(fā)IT事件管理

2023-10-27 08:42:56

Python字典

2023-02-27 12:10:53

2024-03-06 19:57:56

探索商家可視化

2010-08-31 17:08:51

DHCP服務器

2023-10-17 09:36:32

Spark大數(shù)據(jù)

2024-11-28 09:23:09

2025-01-22 14:00:12

點贊
收藏

51CTO技術(shù)棧公眾號