頁面停留時間(Time on Page)簡稱 Tp,是網站分析中很常見的一個指標,用于反映用戶在某些頁面上停留時間的長短,傳統的Tp統計方法會存在一定的統計盲區,比如無法監控單頁應用,沒有考慮用戶切換Tab、最小化窗口等操作場景。 基于上述背景,重新調研和實現了精確統計頁面停留時長的方案,需要 兼容單頁應用和多頁應用,并且不耦合或入侵業務代碼。
我們可以把一個頁面生命周期抽象為三個動作: 「進入」、「活躍狀態切換」、「離開」
如下圖,計算頁面停留時長既如何監控這三個動作,然后在對應觸發的事件中記錄時間戳,比如要統計活躍停留時長就把 active 區間相加即可,要統計總時長既 tn -t0 。
2.1 如何監聽頁面的進入和離開?
對于常規頁面的 首次加載、頁面關閉、刷新 等操作都可以通過 window.onload 和 window.onbeforeunload 事件來監聽頁面進入和離開,瀏覽器前進后退可以通過 pageshow 和 pagehide 處理。
對于單頁應用內部的跳轉可以轉化為兩個問題:1.監聽路由變化,2.判斷變化的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 a popstate event. 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 的實現是基于 hash 的變化,hash 的變化可以通過 hashchange 來監聽
2.1.2 判斷URL是否為不同頁面
問題本質是怎么定義一個頁面,這里我們無法自動獲取,因為不同業務場景定義不同,需要業務方在初始化的時候配置 rules 參數,默認不傳入 rules 的情況取 location.pathname 為 key,key 不相同則判斷為不同的頁面,配置的語法:
new Tracer({ rules: [ { path: '/index' }, { path: '/detail/:id' }, { path: '/user', query: {tab: 'profile'} } ] )
對于頁面進入和離開相關事件整理
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
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 頁面總停留時長
移動端的兼容性目前還沒完全覆蓋;
對于頁面的配置目前還不夠靈活,考慮支持 react-router / vue-router 的配置;
byted-cg-tracer 待封裝;開發中
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/Page_Visibility_API
https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate
因昨天發表了一篇文章官方原版Windows系統鏡像下載方法講述了如何下載微軟官方原版的Windows系統鏡像和Office安裝包的問題,有網友提出質疑說msdn里面下載的才是真正的官方原版。另外有網友說到如何去跟官方發布的哈希值對比是否為原版。這篇文章就此問題將展開講述下如何去辨別Windows產品哈希值是否跟官方發布的一致。
首先來說說何為哈希值。哈希是HASH的直接音譯。將消息或者數據壓縮成摘要,使得數據量變小,將數據的格式固定下來就變為我們常說的哈希值了。通過這種邏輯運算得到的數值具有唯一性,即便是相同文件名得到的哈希值也是不相同的,因此可以說它是文件的唯一身份標識。而在Windows產品上通常是用SHA1來表示哈希值。
首先我在昨天的網站上搜索一個win7英文專業版的ISO系統鏡像,名稱為Windows 7 Professional SP1 (x64) - (English),它的SHA1值為0bcfc54019ea175b1ee51f6d2b207a3d14dd2b58。
然后我們進msdn里面找到相同版本的系統鏡像去對比SHA1哈希值。
上面兩圖的比較可以看出,它們兩的SHA1哈希值是一致的。可以確定是微軟官方原版的系統鏡像。
那如果通過上圖的對比你還是覺得這說明不了問題,那咱們可以進msdn訂戶里面去了解下是不是一致的情況。
msdn訂戶是微軟官方提供給訂閱賬號的一個“下載門戶”,里面是可以查詢到官方發布文件的詳細信息,如果你是msdn訂閱者還可以盡情在里面下載所需的Windows產品。
可以看到msdn訂戶里面的SHA1值也是跟前面兩者一致的。再次驗證到是官方原版的系統鏡像文件。而對于其他的系統鏡像你也可以去驗證是否一致。關于如何辨別SHA1值,到這里你get到技能了么?
所以昨天推薦的那個網站的確是值得大家去使用。無論是系統鏡像的豐富程度還是便利性都是其他的網站不可比擬的。