用戶停留時(shí)長(zhǎng)打點(diǎn)

引子

移動(dòng)看家運(yùn)營(yíng)頁面,投放在和家親/一級(jí)掌廳/微信/等渠道。以前接入的是和家親的打點(diǎn)方案,現(xiàn)在需要增加安防的打點(diǎn)方案,重點(diǎn)記錄指標(biāo):用戶停留時(shí)長(zhǎng)。

初始思路

停留時(shí)長(zhǎng)的打點(diǎn)方案思路非常清晰:

第一步:在用戶進(jìn)入頁面時(shí)記錄時(shí)間點(diǎn)(在頁面加載后記錄)

第二步:在用戶離開頁面時(shí)記錄時(shí)間點(diǎn) (在頁面即將卸載時(shí)記錄)

第三步:用時(shí)間點(diǎn)計(jì)算時(shí)長(zhǎng),并將信息通過打點(diǎn)接口發(fā)送給平臺(tái)進(jìn)行記錄


項(xiàng)目實(shí)戰(zhàn)

離開頁面事件:onbeforeunload

window.onbeforeunload = funcRef

當(dāng)瀏覽器窗口關(guān)閉或者刷新時(shí),會(huì)觸發(fā)beforeunload事件。當(dāng)前頁面不會(huì)直接關(guān)閉,可以點(diǎn)擊確定按鈕關(guān)閉或刷新,也可以取消關(guān)閉或刷新。

代碼示例:

window.addEventListener('beforeunload', (event) => {
  // Cancel the event as stated by the standard.
  event.preventDefault();
  // Chrome requires returnValue to be set.
  event.returnValue = '';
});

注意點(diǎn):

從2011年5月25日起, HTML5 規(guī)范 聲明:在該事件的處理函數(shù)中調(diào)用下列彈窗相關(guān)的方法時(shí),可以忽略不執(zhí)行,window.showModalDialog(), window.alert(), window.confirm() window.prompt().(無法用alert來確認(rèn)是否進(jìn)去了該事件)

需要指出的是,許多瀏覽器會(huì)忽略該事件并自動(dòng)關(guān)閉頁面無需用戶的確認(rèn)。火狐瀏覽器在配置頁面about:config設(shè)有一個(gè)dom.disable_beforeunload的開關(guān)變量用于開啟這個(gè)功能。

瀏覽器兼容性:
移動(dòng)端兼容性很差,safari ,webview中都進(jìn)入不到該事件。

移動(dòng)端離開頁面事件:onpagehide

window.onpagehide = event => {//...}

不要寫在組件里面的unmount事件中,因?yàn)閷?shí)際的使用情況不止是在組件內(nèi)部進(jìn)行頁面跳轉(zhuǎn),還有可能跳轉(zhuǎn)到外部項(xiàng)目鏈接,或者直接關(guān)閉頁面。

移動(dòng)端調(diào)試

怎樣在移動(dòng)端進(jìn)行調(diào)試,確定用戶離開頁面的時(shí)候進(jìn)入到了對(duì)應(yīng)的事件呢?
我的方法是,在事件中設(shè)置對(duì)應(yīng)的localstorage,離開頁面后再次進(jìn)去,看下是否設(shè)置成功即可。

遇到的問題

請(qǐng)求會(huì)丟失

  1. 在PC端Chorme瀏覽器調(diào)試發(fā)現(xiàn):頁面跳轉(zhuǎn)時(shí)打點(diǎn)請(qǐng)求狀態(tài)時(shí)canceled,未發(fā)送成功,關(guān)閉瀏覽器時(shí)打點(diǎn)請(qǐng)求發(fā)送成功。

  2. 在和家親webview中,ios端打點(diǎn)未發(fā)送成功,但是平臺(tái)有收到零星的時(shí)長(zhǎng)打點(diǎn),說明在某些機(jī)型打點(diǎn)請(qǐng)求發(fā)送成功了。但是這種方法不能保證請(qǐng)求一定被發(fā)出了,繼續(xù)尋找解決方案。

解決方案

  1. 服務(wù)器端配置ignore_user_abort防止接口cancel —— 需要服務(wù)端進(jìn)行配置,暫不使用。

  2. 將打點(diǎn)請(qǐng)求改成同步請(qǐng)求,缺點(diǎn)是由于請(qǐng)求是同步的,在請(qǐng)求時(shí)間內(nèi)會(huì)阻塞頁面關(guān)閉或跳轉(zhuǎn)。

    方法:

  • ajax調(diào)用設(shè)置async:false
  • xhr 調(diào)用設(shè)置 var request = new XMLHttpRequest(); request.open('GET', 'http://www.mozilla.org/', false);

結(jié)果:均無請(qǐng)求發(fā)送記錄,查閱資料,因?yàn)檫@種操作會(huì)阻塞頁面,部分高級(jí)瀏覽器已經(jīng)不在支持在頁面卸載時(shí)間中調(diào)用同步請(qǐng)求。

  1. 卸載事件中設(shè)置圖片src為打點(diǎn)地址。缺點(diǎn)是由于請(qǐng)求是同步的,在請(qǐng)求時(shí)間內(nèi)會(huì)阻塞頁面關(guān)閉或跳轉(zhuǎn)。

  2. 在頁面卸載事件中將參數(shù)通過bridge傳給native,讓native去和平臺(tái)通信。缺點(diǎn):只能解決在native中的頁面打點(diǎn)事件,無法同步解決其他場(chǎng)景下的打點(diǎn)遺漏問題。

  1. 終極解決方案
    sendBeacon

navigator.sendBeacon() 方法可用于通過HTTP將少量數(shù)據(jù)異步傳輸?shù)絎eb服務(wù)器。

這個(gè)方法主要用于滿足統(tǒng)計(jì)和診斷代碼的需要,這些代碼通常嘗試在卸載(unload)文檔之前向web服務(wù)器發(fā)送數(shù)據(jù)。過早的發(fā)送數(shù)據(jù)可能導(dǎo)致錯(cuò)過收集數(shù)據(jù)的機(jī)會(huì)。然而,對(duì)于開發(fā)者來說保證在文檔卸載期間發(fā)送數(shù)據(jù)一直是一個(gè)困難。因?yàn)橛脩舸硗ǔ?huì)忽略在 unload (en-US) 事件處理器中產(chǎn)生的異步 XMLHttpRequest。

為了解決這個(gè)問題, 統(tǒng)計(jì)和診斷代碼通常要在 unload 或者 beforeunload (en-US) 事件處理器中發(fā)起一個(gè)同步 XMLHttpRequest 來發(fā)送數(shù)據(jù)。同步的 XMLHttpRequest 迫使用戶代理延遲卸載文檔,并使得下一個(gè)導(dǎo)航出現(xiàn)的更晚。下一個(gè)頁面對(duì)于這種較差的載入表現(xiàn)無能為力。

有一些技術(shù)被用來保證數(shù)據(jù)的發(fā)送。其中一種是通過在卸載事件處理器中創(chuàng)建一個(gè)圖片元素并設(shè)置它的 src 屬性的方法來延遲卸載以保證數(shù)據(jù)的發(fā)送。因?yàn)榻^大多數(shù)用戶代理會(huì)延遲卸載以保證圖片的載入,所以數(shù)據(jù)可以在卸載事件中發(fā)送。另一種技術(shù)是通過創(chuàng)建一個(gè)幾秒鐘的 no-op 循環(huán)來延遲卸載并向服務(wù)器發(fā)送數(shù)據(jù)。

這些技術(shù)不僅編碼模式不好,其中的一些甚至并不可靠而且會(huì)導(dǎo)致非常差的頁面載入性能。

官方示例

window.addEventListener('unload', logData, false);

function logData() {
    navigator.sendBeacon("/log", analyticsData);
}

data 參數(shù)是將要發(fā)送的 ArrayBufferView 或 Blob, DOMString 或者 FormData 類型的數(shù)據(jù)。

缺點(diǎn)是不能設(shè)置復(fù)雜的請(qǐng)求頭,數(shù)據(jù)格式也有要求。

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容