<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【W(wǎng)eb技術(shù)】677- 如何精確統(tǒng)計(jì)頁(yè)面停留時(shí)長(zhǎng)

          共 3837字,需瀏覽 8分鐘

           ·

          2020-08-06 11:46

          來源:字節(jié)跳動(dòng)技術(shù)團(tuán)隊(duì)

          https://mp.weixin.qq.com/s/eLPWGqR6hOYVrwfa3OEVMA

          01

          背景


          頁(yè)面停留時(shí)間(Time on Page)簡(jiǎn)稱 Tp,是網(wǎng)站分析中很常見的一個(gè)指標(biāo),用于反映用戶在某些頁(yè)面上停留時(shí)間的長(zhǎng)短,傳統(tǒng)的Tp統(tǒng)計(jì)方法會(huì)存在一定的統(tǒng)計(jì)盲區(qū),比如無法監(jiān)控單頁(yè)應(yīng)用,沒有考慮用戶切換Tab、最小化窗口等操作場(chǎng)景?;谏鲜霰尘埃匦抡{(diào)研和實(shí)現(xiàn)了精確統(tǒng)計(jì)頁(yè)面停留時(shí)長(zhǎng)的方案,需要 兼容單頁(yè)應(yīng)用和多頁(yè)應(yīng)用,并且不耦合或入侵業(yè)務(wù)代碼。


          02

          分析


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


          如下圖,計(jì)算頁(yè)面停留時(shí)長(zhǎng)既如何監(jiān)控這三個(gè)動(dòng)作,然后在對(duì)應(yīng)觸發(fā)的事件中記錄時(shí)間戳,比如要統(tǒng)計(jì)活躍停留時(shí)長(zhǎng)就把 active 區(qū)間相加即可,要統(tǒng)計(jì)總時(shí)長(zhǎng)既 tn -t0 。



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

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


          • load / beforeunload

          • pageshow / pagehide


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

          ? 1.監(jiān)聽路由變化

          ? 2.判斷變化的URL是否為不同頁(yè)面 。


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

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


          browserHistory

          路由的變化本質(zhì)都會(huì)調(diào)用 History.pushState() 或 History.replaceState() ,能監(jiān)聽到這兩個(gè)事件就能知道。通過 popstate 事件能解決一半問題,因?yàn)?popstate 只會(huì)在瀏覽器前進(jìn)后退的時(shí)候觸發(fā),當(dāng)調(diào)用 history.pushState() or history.replaceState() 的時(shí)候并不會(huì)觸發(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).


          這里需要通過猴子補(bǔ)丁(Monkeypatch)解決,運(yùn)行時(shí)重寫 history.pushState 和 history.replaceState 方法:


          hashHistory

          hashHistory的實(shí)現(xiàn)是基于 hash 的變化,hash 的變化可以通過 hashchange 來監(jiān)聽


          2.1.2?如何定義頁(yè)面(判斷URL是否為不同頁(yè)面)


          方案1: 客戶端定義

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



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

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

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



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



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

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


          2.2.1 Page Visibility API

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

          2.2.2?onblur/onfocus

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



          2.3 什么時(shí)機(jī)上報(bào)數(shù)據(jù)?

          2.3.1 頁(yè)面離開時(shí)上報(bào)

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


          2.3.2 下次打開頁(yè)面時(shí)上報(bào)

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


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


          03

          設(shè)計(jì)



          3.1 UML類關(guān)系圖

          Tracer
          核心類,用來實(shí)例化一個(gè)監(jiān)控,對(duì)原生事件和自定義事件的封裝,監(jiān)聽 enter activechange exit 事件來操作當(dāng)前 Page 實(shí)例。

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


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



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


          04

          兼容性


          Desktop

          Chrome

          Edge

          Firefox

          IE

          Opera


          Safari


          33

          Yes

          18

          11

          15

          7


          Mobile

          Android

          iOS

          Android 4+

          iOS 8+


          05

          思考


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

          ? 1. active 頁(yè)面活躍時(shí)長(zhǎng)

          ? 2. visible 頁(yè)面可見時(shí)長(zhǎng) //僅支持Desktop
          ? 3. duration 頁(yè)面總停留時(shí)長(zhǎng)



          06

          參考


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

            /WindowEventHandlers/onhashchange

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

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

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




          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設(shè)計(jì)模式 重溫系列(9篇全)
          4.?正則 / 框架 / 算法等 重溫系列(16篇全)
          5.?Webpack4 入門(上)||?Webpack4 入門(下)
          6.?MobX 入門(上)?||??MobX 入門(下)
          7.?70+篇原創(chuàng)系列匯總

          回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~

          點(diǎn)擊“閱讀原文”查看70+篇原創(chuàng)文章

          點(diǎn)這,與大家一起分享本文吧~
          瀏覽 111
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操美少妇母亲aV | 欧美日韩A片 | 逼视频网站 | 奇米成人网 | 日韩黄色免费电影 |