摘要:關于首屏首屏時間是指從轉向該頁面到屏幕中該頁面所有內容都可見時的時間。如在事件處理函數中,計算高度,如果大于屏幕高度則意味著首屏的結構已渲染完畢,開始計算首屏時間。
關于首屏
首屏時間是指從轉向該頁面到屏幕中該頁面所有內容都可見時的時間。已經有太多的關于首屏時間的計算,在本文中并不重復闡述這些已經被提出或者實現的方案,而旨在探索與討論更多的首屏自動化采集方案,擴大思考范圍,你我思想之間互相碰撞往往可以激起更多的稀奇古怪的解決方案,這也正是我寫這篇文章的目的。
通過瀏覽器調試工具,我們可以清晰的看出頁面資源加載時序圖:
先是html頁面加載,token進行詞法、語法解析后開始加載靜態資源并執行相關腳本,開始構建DOM樹、render樹和CSSOM數,最后加載圖片,用戶看到完整的網頁。
雖然瀏覽器有著各自的優化的解決方案,但是大多數情況下圖片往往是最后加載完畢,這不僅僅是由于圖片的大小相對較大,而且圖片的加載與否與DOM結構有著很大的關系。DOM是否構建完畢,render樹中是否渲染以及其他的圖片加載策略有關系可能都會影響圖片加載時序。因此在首屏時間的計算中,我們是以最終首屏圖片的加載時間為節點計算的。
首屏計算 原則1 首屏計算模塊不應該耦合業務線一般而言,首屏計算作為一個抽離出的js腳本多帶帶引用,這個模塊盡量不暴露API給開發者使用,所有的采集端任務都由該模塊完成。這句話可能聽起來像一句廢話,但還是有很多情況可能需要業務人員來進行首屏渲染時間的判斷的,下面將針對這個情形舉一個實際的場景:
隨著MVVM模式的興起,前端異步渲染逐漸流行起來,前端編碼逐漸由面向jQuery編程轉向為面向Vue編程??墒鞘褂肰ue編寫的業務代碼在本地打包后僅僅是一個bundle,此時的HTML文件中只是一個 的占位符而已,那么首屏時間計算模塊該如何準確的計算首屏時間呢?因此首屏時間計算模塊必須知道首屏的DOM結構渲染完畢的時間節點,在這個節點時刻進行計算首屏范圍內的圖片加載時間。 可是如何獲取首屏DOM結構渲染完畢的時間節點呢?這就需要業務開發人員制定。在更新vue實例的data屬性后,通知首屏計算模塊此時DOM接口已渲染完畢,開始計算首屏時間。
MVVM開發模式下,首屏時間的計算已經耦合了業務代碼,雖然可以在保證首屏時間的準確性,但卻給開發者帶來了一些可觀判斷邏輯,而這些判斷往往會困擾新入職的同志們,因此我們的目標之一就是解決需要手動打點進行首屏時間計算的現狀。
原則2 性能與準確性的權衡業界有個通過canvas截屏并通過輪詢對比不同時間點截屏圖片之間某幾個隨機像素點,從而判斷首屏是否加載完畢。這種方式雖然科學,但是估計沒有幾個公司會采用這種方案。通過canvas截屏這個操作對硬件的要求可能就比較高,而且需要進行額外的像素運算,因此性能肯定很差。其實這種場景在工程領域經常出現,工程不同于科學那般嚴謹,我們只需要找到給定條件的最優解即可,做工程也就是在做trade off。因此這種對比方案我們也必須摒棄。
實現再次強調,由開發者打點首屏DOM渲染完畢進行首屏時間計算的方式是相對準確的方式,因此我們后續討論的自動化計算首屏時間的準確性都是基于此標準進行對比說明,因為自動化計算肯定是沒有人工干預準確的,這一點毫無疑問。
輪訓采集大法仍然是輪訓,不同的是在每次輪詢中執行一些操作:
獲取首屏的所有圖片(包括IMG標簽與css相關屬性)
綁定首屏圖片的onload和onerror事件,每次輪詢不會重復綁定已綁定的圖片
相同圖片不需重復綁定事件偵聽,否則會與 2 中的每次輪詢混淆
圖片的事件處理函數執行打點信息并統計圖片加載狀態,同時比對時間戳得到最遲加載的時間
具體的實現中,需要特別注意首屏出現的相同圖片的情況。筆者起初在獲取首屏圖片中簡單計算圖片的url數組,存儲重復圖片的個數,并且與該圖片的加載狀態綁定在一起。如首屏中出現了3張相同的圖片,那么在該圖片onload或onerror中對已加載圖片的數量做 加3 處理,否則導致最終的 已加載圖片總數 與 首屏圖片總數 不相等的情況發生。這種實現導致邏輯非常的差,且實現復雜。后通過存儲圖片所在的DOM對象數組實現更為簡單的圖片狀態判斷,更加已讀。
偽代碼如下:
// totalCounter為輪詢的總時間 // DemandCounter是規定的輪詢總時間,為3000ms // imgsLoadedCount則為首屏已加載的圖片數量 // lastImageLoadedStamp為最后加載的圖片時間戳 function checkFirstScreenDomReady(){ if(totalCounter >= DemandCounter){ // ... var stamps = Object.keys(pools), len = stamps.length, i = 0, it; finalImgCount = pools[stamps[len - 1]].imgLen; pollEnd = true; for(;iwatch dog采集= finalImgCount){ self.onRecord = true; _perfQueue._firstScreenLoadEnd = lastImageLoadedStamp; firstScreen.firstScreenLoadEnd = lastImageLoadedStamp; firstScreen.duaring = lastImageLoadedStamp - performance.timing.navigationStart; reportData(firstScreen); return; } } return; } var imgEls = getImage(); imgEls.forEach(function(el) { if(!imgLoadedHash.get(el)){ var img = new Image(); imgLoadedHash.put(el,{ loaded: true, }); img.onload = OnLoad; img.onerror = OnError; img.src = el.__src; } }); pools[totalCounter+""] = { imgLen: imgEls.length, stamp: Date.now(), imgsLoadedCount: imgsLoadedCount }; totalCounter += timeout; }
利用Mutation Observer API進行偵聽 內容框的DOM事件,判斷首屏DOM結構是否完備;如果構建完畢則偵聽首屏范圍內的圖片加載事件,計算首屏時間。
watch dog需要知曉合適首屏DOM構建完畢。這需要首屏計算模塊主動插入一個打點標簽 ,將業務代碼放置在標簽內部(這個步驟最好放在發布階段,由腳手架操作)。通過mutation 偵聽 .j_collector_container 容器的DOM子孫節點變化。如在observe事件處理函數中,計算 .j_collector_container 高度,如果大于屏幕高度則意味著首屏的DOM結構已渲染完畢,開始計算首屏時間。
在計算 .j_collector_container 高度時,最好采用限流策略,防止短時間內計算多次容器的布局信息,這也是無可奈何之舉。
此處的偽代碼如下:
// 記錄首屏DOM元素的位置信息 var firstScreenDomReady = false; var callback = function(records){ if(firstScreenDomReady) return; // 此處需做throttle 處理 for(var i=0,len=records.length;i總結= screenHeight){ firstScreenDomReady = true; recordFirstScreenLoad(); return; } } }; var mo = new MutationObserver(callback); var option = { "childList": true, "subtree": true }; var collectWrapper = document.querySelector(".j_collector_wrapper"); if(collectWrapper.getBoundingClientRect().height < win.innerHeight){ mo.observe(collectWrapper, option); }else{ setTimeout(function(){ recordFirstScreenLoad(); }); }
不管采用哪種方式,計算出來的首屏時間都不是準確的。而且在每種實現中都需要通過JS引擎與渲染引擎的bridge進行通信執行耗時的操作,如getBoundingClientRect和訪問offsetTop屬性導致relayout。不過這也是沒有辦法的辦法,在瀏覽器不提供相關首屏API的前提下我們只有這么做。
另外,對比這三種實現(開發者手動打點、輪訓、watch dog采集),針對一個復雜的電商首屏做了性能測試,該頁面首屏部分有7個非常復雜的子組件,得到如下結果:
結果也符合我們的預期。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/51755.html
摘要:關于首屏首屏時間是指從轉向該頁面到屏幕中該頁面所有內容都可見時的時間。如在事件處理函數中,計算高度,如果大于屏幕高度則意味著首屏的結構已渲染完畢,開始計算首屏時間。 關于首屏 首屏時間是指從轉向該頁面到屏幕中該頁面所有內容都可見時的時間。已經有太多的關于首屏時間的計算,在本文中并不重復闡述這些已經被提出或者實現的方案,而旨在探索與討論更多的首屏自動化采集方案,擴大思考范圍,你我思想之間...
摘要:性能統計有助于幫我們檢測網站的用戶體驗。這樣,我們就輕輕松松的統計到了首屏時間。下一章,我們將繼續聊聊百度移動版首頁那些事。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼): https://segmentfault.com/blog/frontenddriver 上一篇文章我們討論了,如何進行前端日志打點統計: https://segm...
摘要:性能統計有助于幫我們檢測網站的用戶體驗。這樣,我們就輕輕松松的統計到了首屏時間。下一章,我們將繼續聊聊百度移動版首頁那些事。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼): https://segmentfault.com/blog/frontenddriver 上一篇文章我們討論了,如何進行前端日志打點統計: https://segm...
摘要:如何在新的技術背景下讓前端數據采集工作更加完善高效,是本文討論的重點。具體來說,我們對前端的數據采集具體主要分為路由切換性能資源錯誤日志上報路由切換等前端技術的快速發展使單頁面應用盛行。 隨著業務的快速發展,我們對生產環境下的問題感知能力越來越關注。作為距離用戶最近的一層,前端的表現是否可靠、穩定、好用,很大程度上決定著用戶對整個產品的體驗和感受。因此,對于前端的監控不容忽視。 搭建一...
閱讀 3192·2023-04-26 01:39
閱讀 3345·2023-04-25 18:09
閱讀 1612·2021-10-08 10:05
閱讀 3228·2021-09-22 15:45
閱讀 2758·2019-08-30 15:55
閱讀 2393·2019-08-30 15:54
閱讀 3167·2019-08-30 15:53
閱讀 1324·2019-08-29 12:32