本文發表在 微店前端團隊 blog
作者:劉遠洋
公司:微店 – 前端團隊
日期:2018-03-05
背景
在前端效能資料的獲取方法上,現在業內大多使用手動埋點的方式,即在程式碼中,人工判斷首屏完成的位置,並在該處新增首屏記錄的程式碼,類似:firstscreen.report()
這樣。
這樣做的簡單省事,但缺點也很明顯:
-
和業務程式碼混用
通用的監控需求混入了業務程式碼中
-
覆蓋不完整
需要頁面開發者自覺手動新增埋點程式碼,在業務中埋點覆蓋率不一定能達到 100%
-
準確性不一定高
由於需要開發者自行判斷統計指令碼放置的位置,就會存在一些不準確的情況,因為每個人對首屏的理解不同
基於上面的分析,我們近期嘗試了一些方案,試圖將首屏時間計算自動化,節省人力、並提高準確性。
定義
對首屏時間的定義,每個公司可能會有所不同,在本文中,首屏時間指的是:
-
如果頁面首屏有圖片
首屏時間 = 首屏圖片全部載入完畢的時刻 - window.performance.timing.navigationStart 複製程式碼
-
如果頁面首屏沒有圖片
首屏時間 = 頁面處於穩定狀態前最後一次 dom 變化的時刻 - window.performance.timing.navigationStart 複製程式碼
實現原理
總體思路為:
-
從頁面載入開始,按照一定的間隔打點,不斷記錄各個時刻下頁面首屏圖片列表和其他資訊
問題:按照怎樣的間隔打點?
-
找出頁面首屏處於穩定狀態的時刻 T1(到這個時刻為止,頁面首屏可能已經穩定了一段時間)
問題:如何找出這個 T1?
-
以 T1 時刻的首屏圖片數量為準,向前倒推,找到所有打點中最後一次和 T1 時刻首屏圖片一致的打點時刻 T2
-
統計 T2 時刻的所有圖片載入完成時間 T3
-
T3 即為首屏完成的時刻,進行上報
下面,一個個解決上文中提到的問題:
-
問題:如何找出首屏處於穩定狀態的時刻 T1?
我們將頁面從載入到渲染分為兩大階段:1. 獲取資料;2. 資料獲取完畢,渲染頁面。
這個邏輯符合絕大部分的頁面邏輯:先獲取資料,再渲染頁面。
解決方案:
-
通過 AOP 切面方式監聽 XHR 的 send 物件,抓取頁面中的第一個 XHR 請求,以第一個 XHR 請求發出的時刻為起點,統計在 1000ms 以內所有發出的請求到陣列 Request 中。
我們認為可能影響首屏的請求在
[第一個 xhr 請求發出的時刻,第一個 xhr 請求發出的時刻 + 1000ms]
的時間段內均已發出。 -
針對串聯型的請求(即下一個請求依賴上一個請求的返回資料),同時統計每個請求返回後,500ms 以內新發出的請求到陣列 Request 中。
有些頁面的資料請求方式是序列的,可能經過兩個串聯的請求後首屏的資料才能載入。
影響首屏的請求可能也會以這樣的形式發出。
-
陣列 Request 中統計到的請求,基本包含了所有影響首屏的資料請求,同時也包含了部分不影響首屏的資料請求。
-
針對上述統計到的請求,找到所有資料返回的時刻 T1,然後,
T1 = T1 + 300ms
,保證頁面接收資料後渲染完畢(300ms 用於一次渲染足夠了)。 -
此時的 T1 時刻,頁面首屏被認為處於穩定狀態。
-
-
問題:按照怎樣的間隔打點?
-
MutationObserver
大家都知道 MutationObserver 物件用於捕捉頁面 dom 變化,因此在指令碼中,我們使用了 MutationObserver 監聽 dom 變化,並在每次 dom 變化時觸發一次打點(統計該時刻首屏圖片資訊)
-
setInterval
setInterval 也能實現定時打點
-
MutationObserver 和 setInterval 組合
但 MutationObserver 回撥函式的觸發時機開發者並不可控,有幾種情況:
- 兩次回撥之間可能距離幾百毫秒甚至 1秒多,導致統計誤差較大
- 某些情況下,dom 不再變化,但頁面元素中,
img
的src
發生了變化或元素的background-image
發生了變化,並不會觸發在 MutationObserver 的回撥,導致統計失誤
因此,我們現在的方案是結合 MutationObserver 和 setInterval,在 MutationObserver 回撥的間歇,啟動 setInterval,保證頁面載入過程中打點間隔不會過長,提高統計準確率。
-
統計誤差
即使使用了上述複雜的打點與判斷,誤差仍然存在,那麼,誤差到底在哪裡?
如下圖所示:
不穩定狀態(1 images) 穩定狀態2(2 images) 穩定狀態1(2 images)
| | |
|________________________|_______________________|
t1 t2 t3
複製程式碼
按照上面的理論,我們會取 t2
時刻為可以統計首屏的時刻,兩張圖片載入完成的時刻即為首屏完成的時刻。
t2
和 t1
時刻差了 1 張圖片。
按照我們的理論,首屏完成時間一定在 t2 之後的某個時刻 t2.n
。
而實際相差的那張圖片,什麼時候載入完成的,我們不得而知,可能在 t2
前已經載入完畢了,也可能已經發出請求,但還沒載入完畢。
誤差就在這裡,它總會存在。
但我們需要統計的是在誤差可以接受範圍內的首屏資料,根據在公司業務實踐的反饋來看,資料可靠性很高。
Talk is cheap, show me the code
我們也開源了這個小工具:
github: auto-compute-first-screen-time
npm: auto-compute-first-screen-time
歡迎小夥伴們使用,吐槽,改進。