前端埋點統計方案思考

埋點即監控用戶在應用表現層的行爲,於產品迭代而言相當重要。埋點數據分析是產品需求的 來源 ,檢驗功能是否達預期的 佐證 。前端較服務端更接近用戶,本小白將在此對前端埋點統計方案述說一二。html

採集埋點數據可作以下分析(以百度統計爲例):前端

用戶屬性用戶行爲 轉化各種可視化圖表:vue

不一樣產品對數據的關注角度不一樣,可按需採集。如信息流產品對停留時長的關注度更高(統計頁面訪問 & 跳出時間),商城類較注重「復購率」(統計新老用戶),廣告類更追求最大限度。git

埋點統計一般分兩類:github

  • 頁面訪問量統計
  • 功能點擊量統計

頁面訪問量統計

頁面訪問量統計一般分兩類:後端

  • PV :頁面訪問人次
  • UV :頁面訪問人數

頁面訪問量,並不是僅僅取決於其內容吸引力,影響因素包含入口 外觀位置深度 等等(在此不考慮剛需)。入口外觀屬 UI 設計範疇,入口位置可經過分析用戶點擊熱力圖調整,入口深度可經過分析用戶訪問路徑調整。api

用戶點擊 熱力圖 形如:緩存

將核心頁面入口置於熱力圖紅色區域?服務器

採集頁面加載 fromto 以獲知用戶訪問路徑:app

分析可知用戶廣泛 訪問深度 、每一深度 & 每一頁面的 流失率 等,依照結果調整核心頁面入口源、入口深度?

頁面訪問量,也並不是僅僅取決於產品設計。倘若 PV 穩定的頁面訪問量 爆跌 ,便需考慮其加載成功率了(或許是枚技術 bug)。


前端如何實現全局 PV 統計,以 Vue 應用爲例。

方案一

經過在入口文件 index.js 全局定義 Router.beforeEach

import App from './app'
import Router from './router'

Router.beforeEach((to, from, next) => {
    App.logEvent({
        type: 'visit',
        name: to.name,
        time: new Date().valueOf(),
        params: {
            from: {
                name: from.name,
                path: from.path,
                query: from.query
            },
            to: {
                name: to.name,
                path: to.path,
                query: to.query
            }
        }
    })
    next()
})

停留時長可經過 (跳轉頁 time - 當前頁 time) 獲知,但關閉應用時如何統計?監聽應用關閉 onbeforeunload + onunload

其中 App.logEvent 爲自定義 Vue 插件 App 中的 method,用於向服務器發起 埋點上報請求

import Request from './utils/request'

const App = {
    // ...
    logEvent (opts) {
        Request({
            url: '/log/event',
            method: 'POST',
            data: {
                type: opts.type,
                name: opts.name,
                time: opts.time,
                params: opts.params || {}
            }
        })
    }
}
App.install = (Vue, options) => {
    Vue.prototype.$app = {
        // ...
        logEvent: App.logEvent
    }
}

export default App

方案二

經過在入口文件 index.js 全局註冊混入 beforeRouteEnterbeforeRouteLeave 對象:

import Vue from 'vue'

Vue.mixin({
    beforeRouteEnter (to, from, next) {
        next(vm => {
            vm.$app.logEvent({
                type: 'visit',
                name: to.name,
                time: new Date().valueOf(),
                params: {
                    from: {
                        name: from.name,
                        path: from.path,
                        query: from.query
                    },
                    to: {
                        name: to.name,
                        path: to.path,
                        query: to.query
                    }
                }
            })
        })
    },
    beforeRouteLeave (to, from, next) {
        this.$app.logEvent({
            type: 'visit',
            name: to.name,
            time: new Date().valueOf(),
            params: {
                from: {
                    name: from.name,
                    path: from.path,
                    query: from.query
                },
                to: {
                    name: to.name,
                    path: to.path,
                    query: to.query
                }
            }
        })
        next()
    }
})

關閉應用時 beforeRouteLeave 是否觸發?

上述方案存在明顯缺陷:

  • 官方曰慎用全局混入對象!!!
  • 對於頁面同名鉤子函數 beforeRouteEnterbeforeRouteLeave ,如何 merge ?如何 next
  • 含子路由的頁面將調用 2beforeRouteEnterbeforeRouteLeave ,PV 無形翻倍...

我猜此刻有打全局混入 createddestroyed 並經過 this.$route 獲知訪問對象主意的人了,試試看?

使人不知所措的輸出,打印次數與 路由表 長度一致嗷~

其中 this.\$app.logEvent(vm.\$app.logEvent) 等同方案一中 App.logEvent ,再也不贅述。


如何恰當選取全局 PV 統計方案?

  • SPA 應用 :僅單入口,在入口文件全局定義 Router.beforeEach 方即可行。
  • MPA 應用 :多入口,在每一個入口文件定義 Router.beforeEach ?可封裝公用邏輯(假裝單入口),免去重複構造 entry 的成本。

  • SPA + MPA 混合應用 :emmmmmm...採用 MPA 應用的統計方案。
  • SSR 應用 :爲追求更好的 SEO 而採用服務端渲染(SSR)。以 Jinja(Python 模板)爲例,調用 TemplateView 則爲渲染頁面(不一樣於先後端分離項目,服務端沒法獲知接口調用與頁面渲染的對應關係),統計其調用次數及 TemplateName 可知頁面 PV。

至於 UV,統計 PV 時採集 userId 去重便可。若應用無用戶管理體系,採集 IPdeviceId 也可粗略得知 UV(不精準)。


功能點擊量統計

不一樣功能的點擊量不一樣,同一功能不一樣區域的點擊量也不一樣:

按鈕點擊量,影響因素包含按鈕 外觀位置入口 等等(在此不考慮剛需)。按鈕外觀屬 UI 設計範疇,按鈕位置可經過分析用戶點擊熱力圖調整,按鈕入口可經過分析觸發源分佈調整。

舉一實例:

運營同窗會將一張圖片裁切成 n 個區域,點擊每一區域所推薦商品不一樣。統計區域點擊座標,據熱力圖調整商品排序以求 利益最大化


前端如何實現功能點擊量統計?

本人將功能點擊分兩類:

  • 帶業務接口請求
  • 無業務接口請求

方案一

將埋點上報混入業務接口請求,無接口請求的點擊採用自定義上報:

其中 param keys 指代需上報的業務請求參數 key list (並不是所有參數均需隨埋點上報)。

上述方案大大節約請求數,但存在明顯缺陷:

  • 將埋點上報混入業務接口,上報 crash 不只丟失統計數據,還將影響主功能。
  • 統計與業務 高耦合 ,二者儘可能不混於同一服務。

方案二

將全部點擊事件視爲同一類,走統一上報接口:

logEvent (opts) {
    Request({
        url: '/log/event',
        method: 'POST',
        data: {
            type: opts.type,
            name: opts.name,
            time: opts.time,
            params: opts.params || {}
        }
    })
}

上述方案也存在明顯缺陷:

  • 請求量翻倍:但統計與業務服務拆分後,請求並不是同一組服務器承擔。
  • 待上報的點擊事件函數均需調用 logEvent :封裝一枚附帶埋點上報的 組件 ,以 Vue 爲例。
<template>
    <div class="vc-trace" @click="triggerClick">
        <slot></slot>
    </div>
</template>

<script>
import Request from './utils/request'

export default {
    name: 'Trace',
    props: {
        type: {
            type: String,
            default: ''
        },
        name: {
            type: String,
            default: ''
        },
        from: {
            type: String,
            default: ''
        },
        params: {
            type: Object,
            default: () => ({})
        }
    },
    methods: {
        triggerClick () {
            Request({
                url: 'XXX/log/event',
                method: 'POST',
                data: {
                    type: this.type,
                    name: this.name,
                    from: this.from,
                    time: new Date().valueOf(),
                    params: this.params
                }
            })
        }
    }
}
</script>

方案本無優劣,適合才更重要,需綜合考慮 產品設計產品使用度服務利用率 等等。例使用度較低應用可將統計與業務混於同一服務以節約成本,使用度較高應用可採起 本地緩存批量上報 以下降服務壓力,但批量上報是否加大統計 偏差

本文所述僅冰山一角,歡迎你們留言寶貴經驗~

2018/12/19 續更

看到幾篇不錯的文章:

頁面跳轉時,統計數據丟失問題探討

Page Lifecycle API 教程


做者:呆戀小喵

個人後花園:https://sunmengyuan.github.io...

個人 github:https://github.com/sunmengyuan

原文連接:https://sunmengyuan.github.io...

相關文章
相關標籤/搜索