如何精確統(tǒng)計頁面停留時長

作者:今日頭條技術(shù)

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

1汰现、背景

頁面停留時間(Time on Page)簡稱 Tp逊笆,是網(wǎng)站分析中很常見的一個指標(biāo)欺矫,用于反映用戶在某些頁面上停留時間的長短,傳統(tǒng)的Tp統(tǒng)計方法會存在一定的統(tǒng)計盲區(qū)虾标,比如無法監(jiān)控單頁應(yīng)用,沒有考慮用戶切換Tab多律、最小化窗口等操作場景刑巧。基于上述背景逆皮,重新調(diào)研和實現(xiàn)了精確統(tǒng)計頁面停留時長的方案宅粥,需要 兼容單頁應(yīng)用和多頁應(yīng)用,并且不耦合或入侵業(yè)務(wù)代碼电谣。

2秽梅、分析

我們可以把一個頁面生命周期抽象為三個動作:「進(jìn)入」抹蚀、「活躍狀態(tài)切換」、「離開」

image

如下圖企垦,計算頁面停留時長既如何監(jiān)控這三個動作环壤,然后在對應(yīng)觸發(fā)的事件中記錄時間戳,比如要統(tǒng)計活躍停留時長就把 active 區(qū)間相加即可钞诡,要統(tǒng)計總時長既 tn -t0 郑现。

image
2.1 如何監(jiān)聽頁面的進(jìn)入和離開?

對于常規(guī)頁面的 首次加載荧降、頁面關(guān)閉接箫、刷新 等操作都可以通過 window.onload 和 window.onbeforeunload 事件來監(jiān)聽頁面進(jìn)入和離開,瀏覽器前進(jìn)后退可以通過 pageshow 和 pagehide 處理朵诫。

  • load / beforeunload

  • pageshow / pagehide

對于單頁應(yīng)用內(nèi)部的跳轉(zhuǎn)可以轉(zhuǎn)化為兩個問題:

  • 監(jiān)聽路由變化

  • 判斷變化的URL是否為不同頁面 辛友。

2.1.1 監(jiān)聽路由變化

目前主流的單頁應(yīng)用大部分都是基于 browserHistory (history api) 或者 hashHistory 來做路由處理,我們可以通過監(jiān)聽路由變化來判斷頁面是否有可能切換拗窃。注意是有可能切換,因為URL發(fā)生變化不代表頁面一定切換泌辫,具體的路由配置是由業(yè)務(wù)決定的(既URL和頁面的匹配規(guī)則)随夸。

browserHistory

路由的變化本質(zhì)都會調(diào)用 History.pushState() 或 History.replaceState() ,能監(jiān)聽到這兩個事件就能知道震放。通過 popstate 事件能解決一半問題宾毒,因為 popstate 只會在瀏覽器前進(jìn)后退的時候觸發(fā),當(dāng)調(diào)用 history.pushState() or history.replaceState() 的時候并不會觸發(fā)殿遂。

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(this, arguments)
    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 的實現(xiàn)是基于 hash 的變化墨礁,hash 的變化可以通過 hashchange 來監(jiān)聽

2.1.2 判斷URL是否為不同頁面

方案1: 客戶端定義

通過業(yè)務(wù)方在初始化的時候配置頁面規(guī)則幢竹,然后JS通過URL匹配不同的規(guī)則來區(qū)分不同的頁面,這種方案在客戶端數(shù)據(jù)上報的時候就已經(jīng)明確了不同的頁面恩静,偽代碼:

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

方案2: 數(shù)據(jù)分析平臺定義

假設(shè)我們最終上報后有一個數(shù)據(jù)分析平臺來展現(xiàn)焕毫,我們可以在類似數(shù)據(jù)平臺來配置頁面規(guī)則,這樣在客戶端實現(xiàn)的代碼邏輯就不需要區(qū)分頁面驶乾,而是每次URL發(fā)生變化就將數(shù)據(jù)上報邑飒,最終通過數(shù)據(jù)平臺配置的頁面URL規(guī)則來求和、過濾數(shù)據(jù)等级乐。

當(dāng)數(shù)據(jù)展現(xiàn)平臺不支持配置URL規(guī)則來區(qū)分頁面的時候疙咸,可以采用方案1;當(dāng)有數(shù)據(jù)平臺支持的時候采用方案2更合理风科;

2.1.3 對于頁面進(jìn)入和離開相關(guān)事件整理

image

2.2 如何監(jiān)聽頁面活躍狀態(tài)切換撒轮?

可以通過 Page Visibility API 以及在 window 上聲明 onblur/onfocus 事件來處理乞旦。

2.2.1 Page Visibility API

一個網(wǎng)頁的可見狀態(tài)可以通過 Page Visibility API 獲取,比如當(dāng)用戶 切換瀏覽器Tab腔召、最小化窗口杆查、電腦睡眠 的時候,系統(tǒng)API會派發(fā)一個當(dāng)前頁面可見狀態(tài)變化的 visibilitychange 事件臀蛛,然后在事件綁定函數(shù)中通過 document.hidden 或者 document.visibilityState 讀取當(dāng)前狀態(tài)亲桦。

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

2.2.2 onblur/onfocus

可以通過 Page Visibility API 以及在 window 上聲明 onblur/onfocus 事件來處理。對于PC端來說浊仆,除了監(jiān)聽上述相關(guān)事件外客峭,還可以考慮監(jiān)聽鼠標(biāo)行為,比如當(dāng)一定時間內(nèi)鼠標(biāo)沒有操作則認(rèn)為用戶處于非活躍狀態(tài)抡柿。

2.3 什么時機上報數(shù)據(jù)舔琅?

2.3.1 頁面離開時上報

對于頁面刷新或者關(guān)閉窗口觸發(fā)的操作可能會造成數(shù)據(jù)丟失

2.3.2 下次打開頁面時上報

會丟失歷史訪問記錄中的最后一個頁面數(shù)據(jù)

目前采用的方案2,對于單頁內(nèi)部跳轉(zhuǎn)是即時上報洲劣,對于單頁/多頁應(yīng)用觸發(fā) window.onbeforeunload 事件的時候會把當(dāng)前頁面數(shù)據(jù)暫存在 localStorage 中备蚓,當(dāng)用戶下次進(jìn)入頁面的時候會把暫存數(shù)據(jù)上報。有個細(xì)節(jié)問題囱稽,如果用戶下次打開頁面是在第二天郊尝,對于統(tǒng)計當(dāng)天的活躍時長會有一定的誤差,所以在數(shù)據(jù)上報的同時會把該條數(shù)據(jù)的頁面進(jìn)入時間/離開時間帶上战惊。

3流昏、設(shè)計

3.1 UML類關(guān)系圖

Tracer

核心類,用來實例化一個監(jiān)控吞获,對原生事件和自定義事件的封裝况凉,監(jiān)聽 enter activechange exit 事件來操作當(dāng)前 Page 實例。

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

Page
頁面的抽象類,用來實例化一個頁面烤黍,封裝了 enter exit active inactive 等操作膛锭,內(nèi)部通過 state 屬性來維護(hù)當(dāng)前頁面狀態(tài)。

image
3.2 事件派發(fā)關(guān)系圖
image

4蚊荣、兼容性

Desktop

image

Mobile

image

5初狰、思考

對于頁面停留時長的定義可能在不同場景會有差異,比如內(nèi)部業(yè)務(wù)系統(tǒng)或者OA系統(tǒng)互例,產(chǎn)品可能更關(guān)心用戶在頁面的活躍時長奢入;而對于資訊類型的產(chǎn)品,頁面可見時長會更有價值。單一的數(shù)據(jù)對業(yè)務(wù)分析是有限的腥光,所以在具體的代碼實過程中我們會把停留時長分三個指標(biāo)关顷,這樣能更好的幫助產(chǎn)品/運營分析。

  • active 頁面活躍時長

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

  • duration 頁面總停留時長

6武福、參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末议双,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捉片,更是在濱河造成了極大的恐慌平痰,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伍纫,死亡現(xiàn)場離奇詭異宗雇,居然都是意外死亡,警方通過查閱死者的電腦和手機莹规,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門赔蒲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人良漱,你說我怎么就攤上這事舞虱。” “怎么了母市?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵矾兜,是天一觀的道長。 經(jīng)常有香客問我窒篱,道長焕刮,這世上最難降的妖魔是什么舶沿? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任墙杯,我火速辦了婚禮,結(jié)果婚禮上括荡,老公的妹妹穿的比我還像新娘高镐。我一直安慰自己,他們只是感情好畸冲,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布嫉髓。 她就那樣靜靜地躺著,像睡著了一般邑闲。 火紅的嫁衣襯著肌膚如雪算行。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天苫耸,我揣著相機與錄音州邢,去河邊找鬼。 笑死褪子,一個胖子當(dāng)著我的面吹牛量淌,可吹牛的內(nèi)容都是我干的骗村。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼呀枢,長吁一口氣:“原來是場噩夢啊……” “哼胚股!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起裙秋,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤琅拌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后残吩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體财忽,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年泣侮,在試婚紗的時候發(fā)現(xiàn)自己被綠了即彪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡活尊,死狀恐怖隶校,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛹锰,我是刑警寧澤深胳,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站铜犬,受9級特大地震影響舞终,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜癣猾,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一敛劝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纷宇,春花似錦夸盟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拓春,卻和暖如春释簿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背硼莽。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工庶溶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓渐尿,卻偏偏與公主長得像醉途,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子砖茸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350