頁面跳轉時,統計資料丟失問題探討

發表於2016-02-21
為了更好地瞭解使用者對產品的使用情況,業務中,我們經常會收到埋點統計的需求,比如:
  • 收集一段時間內使用者游標在頁面中的運動情況,包括游標移動、點選等行為
  • 統計使用者滾屏行為
  • 統計使用者在站點的停留時長
  • 收集頁面連結的點選數量等

無論是移動端還是 PC 端,相信很多朋友都遇到了這麼幾個十分讓人頭疼的問題:

  • 統計某個連結的點選量,但是這個連結點選後直接跳轉走了
  • 統計頁面時長問題,unload 的時候傳送的統計丟失了
  • 統計指令碼還沒有初始化,使用者不感興趣已經走人了等

如果我們把這樣的資料交給了產品同學,可能會讓他們對使用者行為產生錯誤的認知,一定程度上影響產品的下一步改善。

傳統解決方案

上面提到的問題,從技術角度可以歸納為兩點:

  • 使用者關閉頁面過早,統計指令碼還未載入/初始化完成
  • 使用者關閉或者跳出頁面的時候,請求未發出

針對第一點,概率較小,一般的處理方式就是,不要把統計指令碼參合到其他指令碼中,單獨載入,並且放在前頭,讓它優先載入。很多公司的做法是,不讓開發者關心統計指令碼的載入,使用者請求頁面的時候,Nginx 會在 Body 開始標籤位置注入一段指令碼。

對於問題二,處理方案就有很多了。

1. 阻塞式的 Ajax 請求

還記得 XMLHttpRequest::open 方法的第三個引數吧,如果設定為 false 就是同步載入,

阻塞頁面關閉,當然可以在 readState 為 2 的時候就 abort 請求,因為我們不關心響應的內容,只要請求發出去就行了。

2. 暴力的死迴圈

原理跟上面類似,只不過是使用一個空的死迴圈阻塞頁面關閉,

3. 發一個圖片請求阻塞

大部分瀏覽器都會等待圖片的載入,趁這個機會把統計資料傳送出去

以上提到的幾個方案都是一個原理,讓瀏覽器繼續保持阻塞狀態,等資料傳送出去後再跳轉,這裡存在的問題是:

  • 少量瀏覽器下可能不奏效
  • 等待一會兒再跳轉,使用者體驗上打了折扣,尤其是移動端上

是否有更好的方案解決這個問題呢,前端同學秉著「小強精神」也提出了兩個可實踐的方案。

優化方案

不就是埋點統計資料嘛,非得在當前頁面傳送出去?優化方案的思路具有一定的跳躍性,我們考慮將資料在下跳頁中傳送,那麼問題就轉換為,如何將資料傳遞給下跳頁?

對於連結點選量的統計,我們可以將連結資訊通過 url 傳遞給下跳頁,傳遞思路如下:

1. url 傳參

通過陣列標識一個連結的位置資訊,如 [站點id,頁面id,模組id,連結index],通過四個引數可以惟一標識連結位置屬性,使用 URL param 引數將陣列資料傳遞給下跳頁,等待由下跳頁將資料傳送出去。

這裡存在的問題是,下跳頁中必須部署同樣的統計指令碼,但對一個系統來說,這是很容易做到的。我們也不會在自己的網頁上放其他網站的連結吧,所以整個資料的統計都在一個閉環內。

2. 通過 window.name 傳遞資料

window.name 是瀏覽器給我們開放的一個介面,設定該屬性的值後,即便頁面發生了跳轉,這個值依然不會變化,並且可以跨域使用。

這裡存在的問題是,該屬性可能被開發者用於其他途徑。我們可以限制開發者直接使用 window.name,封裝介面,通過介面呼叫,如 aralejs 提供的 nameStorage

儲存形式為:

以上雖然基本解決了資料丟失和體驗差的問題,但是這也很大程度依賴於開發者的程式設計習慣,如不能隨便玩耍 window.name;也對系統有一定的要求,必須在所有頁面上部署同樣的埋點指令碼。

這件事情應該交給瀏覽器來解決

上面提到的各種方案,不乏黑科技,然而存在的問題還是一大堆,如果團隊的開發者執行力不夠,中途容易出現各種麻煩。所以真正能夠解決這個問題的,必然還是瀏覽器本身!

為什麼不能給使用者提供這樣一個 API,即使頁面跳轉了,也能夠將上個頁面的請求發出去呢?慶幸的是,W3C 工作組也想到了這個問題,提出了 Beacon API草案

Beacon API 允許開發者傳送少量錯誤分析和上報的資訊,它的特點很明顯:

  • 在空閒的時候非同步傳送統計,不影響頁面諸如 JS、CSS Animation 等執行
  • 即使頁面在 unload 狀態下,也會非同步傳送統計,不影響頁面過渡/跳轉到下跳頁
  • 能夠被客戶端優化傳送,尤其在 Mobile 環境下,可以將 Beacon 請求合併到其他請求上,一同處理

sendBeacon 函式掛在在 navigator 上,在 unload 之前,這個函式一定是被初始化了的。其使用方式為:

navigator.sendBeacon(url, data);,第一個引數為資料上報的地址,第二個引數為要傳送的資料,支援的資料格式有:ArrayBufferView, Blob, DOMString, 和 FormData。

Beacon 的還有一個非常實用的移動端使用場景,當使用者從瀏覽器切換到其他 app 介面或者 Home 屏的時候,部分瀏覽器預設會停止頁面指令碼的執行,如果在這個時候使用了 unload 時間,可能會讓你失望,因為 unload 事件並不會觸發,此時,Beacon 就派上用途了,它是不會受影響的。

最後

本文是對頁面打點丟失問題的簡單探討,列舉了我們通常會用到的一些解決方案,可能不是很完善,如果你有更好的建議,可以提出來。

很多問題,我們絞盡腦汁,可能很少會考慮,這個問題是不是應該有我們來解決,或者說這個問題交給誰處理是最恰當的。本文的探討可以看到,瀏覽器本身才是最好的問題解決方,當網站流量變大之後,上面提到的丟失問題就更加明顯,這也迫使瀏覽器本身做了改善,自然也在情理之中。

相關文章