如何精確統計用戶在頁面的停留時長?

做者:今日頭條技術
數據庫

連接:https://techblog.toutiao.com/2018/06/05/ru-he-jing-que-tong-ji-ye-mian-ting-liu-shi-chang/api

一、背景


頁面停留時間(Time on Page)簡稱 Tp,是網站分析中很常見的一個指標,用於反映用戶在某些頁面上停留時間的長短,傳統的Tp統計方法會存在必定的統計盲區,好比沒法監控單頁應用,沒有考慮用戶切換Tab、最小化窗口等操做場景。基於上述背景,從新調研和實現了精確統計頁面停留時長的方案,須要 兼容單頁應用和多頁應用,而且不耦合或入侵業務代碼。瀏覽器


二、分析


咱們能夠把一個頁面生命週期抽象爲三個動做:「進入」、「活躍狀態切換」、「離開」微信


以下圖,計算頁面停留時長既如何監控這三個動做,而後在對應觸發的事件中記錄時間戳,好比要統計活躍停留時長就把 active 區間相加便可,要統計總時長既 tn -t0 。
數據結構

2.1 如何監聽頁面的進入和離開?

對於常規頁面的 首次加載、頁面關閉、刷新 等操做均可以經過 window.onload 和 window.onbeforeunload 事件來監聽頁面進入和離開,瀏覽器前進後退能夠經過 pageshow 和 pagehide 處理。併發

  • load / beforeunloadapp

  • pageshow / pagehideide

對於單頁應用內部的跳轉能夠轉化爲兩個問題:函數

  • 監聽路由變化微服務

  • 判斷變化的URL是否爲不一樣頁面 。

2.1.1 監聽路由變化


目前主流的單頁應用大部分都是基於 browserHistory (history api) 或者 hashHistory 來作路由處理,咱們能夠經過監聽路由變化來判斷頁面是否有可能切換。注意是有可能切換,由於URL發生變化不表明頁面必定切換,具體的路由配置是由業務決定的(既URL和頁面的匹配規則)。

browserHistory

路由的變化本質都會調用 History.pushState() 或 History.replaceState() ,能監聽到這兩個事件就能知道。經過 popstate 事件能解決一半問題,由於 popstate 只會在瀏覽器前進後退的時候觸發,當調用 history.pushState() or history.replaceState() 的時候並不會觸發。

The popstate event is fired when the active history entry changes. If the history entry being activated was created by a call to history.pushState() or was affected by a call to history.replaceState(), the popstate event’s state property contains a copy of the history entry’s state object.

Note that just calling history.pushState() or history.replaceState() won’t trigger apopstateevent. The popstate event will be triggered by doing a browser action such as a click on the back or forward button (or calling。history.back() or history.forward() in JavaScript).

這裏須要經過猴子補丁(Monkeypatch)解決,運行時重寫 history.pushState 和 history.replaceState 方法:


let _wr =  function (type{  
  let orig = window.history[type]
  return  function ({
    let rv = orig.apply(thisarguments)
    let e = new Event(type.toLowerCase())
    e.arguments = arguments
    window.dispatchEvent(e)
    return rv
  }}
window.history.pushState = _wr('pushState')  
window.history.replaceState = _wr('replaceState')
window.addEventListener('pushstate',  function (event{})  
window.addEventListener('replacestate',  function (event{})


hashHistory

hashHistory 的實現是基於 hash 的變化,hash 的變化能夠經過 hashchange 來監聽


2.1.2 判斷URL是否爲不一樣頁面


方案1: 客戶端定義


經過業務方在初始化的時候配置頁面規則,而後JS經過URL匹配不一樣的規則來區分不一樣的頁面,這種方案在客戶端數據上報的時候就已經明確了不一樣的頁面,僞代碼:

new Tracer({  
  rules: [
    { path: '/index' },
    { path'/detail/:id' },
    { path'/user', query: {tab: 'profile'} }
  ])


方案2: 數據分析平臺定義


假設咱們最終上報後有一個數據分析平臺來展示,咱們能夠在相似數據平臺來配置頁面規則,這樣在客戶端實現的代碼邏輯就不須要區分頁面,而是每次URL發生變化就將數據上報,最終經過數據平臺配置的頁面URL規則來求和、過濾數據等。

當數據展示平臺不支持配置URL規則來區分頁面的時候,能夠採用方案1;當有數據平臺支持的時候採用方案2更合理;


2.1.3 對於頁面進入和離開相關事件整理



2.2 如何監聽頁面活躍狀態切換?

能夠經過 Page Visibility API 以及在 window 上聲明 onblur/onfocus 事件來處理。


2.2.1 Page Visibility API

一個網頁的可見狀態能夠經過 Page Visibility API 獲取,好比當用戶 切換瀏覽器Tab、最小化窗口、電腦睡眠 的時候,系統API會派發一個當前頁面可見狀態變化的 visibilitychange 事件,而後在事件綁定函數中經過 document.hidden 或者 document.visibilityState 讀取當前狀態。

document.addEventListener('visibilitychange',  function (event{  
  console.log(document.hidden, document.visibilityState)})


2.2.2 onblur/onfocus

能夠經過 Page Visibility API 以及在 window 上聲明 onblur/onfocus 事件來處理。對於PC端來講,除了監聽上述相關事件外,還能夠考慮監聽鼠標行爲,好比當必定時間內鼠標沒有操做則認爲用戶處於非活躍狀態。


2.3 什麼時機上報數據?


2.3.1 頁面離開時上報

對於頁面刷新或者關閉窗口觸發的操做可能會形成數據丟失


2.3.2 下次打開頁面時上報

會丟失歷史訪問記錄中的最後一個頁面數據

目前採用的方案2,對於單頁內部跳轉是即時上報,對於單頁/多頁應用觸發 window.onbeforeunload 事件的時候會把當前頁面數據暫存在 localStorage 中,當用戶下次進入頁面的時候會把暫存數據上報。有個細節問題,若是用戶下次打開頁面是在次日,對於統計當天的活躍時長會有必定的偏差,因此在數據上報的同時會把該條數據的頁面進入時間/離開時間帶上。


三、設計


3.1 UML類關係圖

Tracer

核心類,用來實例化一個監控,對原生事件和自定義事件的封裝,監聽 enter activechange exit 事件來操做當前 Page 實例。

P.S. 取名來自暴雪旗下游戲守望先鋒英雄獵空(Tracer),直譯爲:追蹤者。

Page
頁面的抽象類,用來實例化一個頁面,封裝了 enter exit active inactive 等操做,內部經過 state 屬性來維護當前頁面狀態。

3.2 事件派發關係圖

四、兼容性

Desktop

Mobile

五、思考

對於頁面停留時長的定義可能在不一樣場景會有差別,好比內部業務系統或者OA系統,產品可能更關心用戶在頁面的活躍時長;而對於資訊類型的產品,頁面可見時長會更有價值。單一的數據對業務分析是有限的,因此在具體的代碼實過程當中咱們會把停留時長分三個指標,這樣能更好的幫助產品/運營分析。

  • active 頁面活躍時長

  • visible 頁面可見時長 //僅支持Desktop

  • duration 頁面總停留時長

六、參考

  • https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onhashchange

  • https://developer.mozilla.org/en-US/docs/Web/Events/popstate

  • https://developer.mozilla.org/en-US/docs/Web/API/PageVisibilityAPI

  • https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate

   
   
      
      
       
       
                
       
   
      
關注公衆號,查看更多優質文章

最近,整理一份Java資料 Java從0到1 ,覆蓋了Java核心技術、JVM、Java併發、SSM、微服務、數據庫、數據結構等等。
獲取方式:關注公衆號並回復  Java  領取,更多Java內容陸續奉上。
明天見(。・ω・。)ノ♡

本文分享自微信公衆號 - 程序IT圈(DeveloperIT)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索