关于首屏时间采集自动化解决方案
时间:2023-04-02 11:48:50
HTML
关于首屏首屏时间是指从翻到页面到页面所有内容都出现在屏幕上的时间。关于首屏时间的计算已经太多了。在本文中,我不会重复这些提出或实现的方案,而是探索和讨论更多首屏自动采集方案,拓展思路。你我都认为相互碰撞往往能激发出更古怪的解决方案,这也正是我写这篇文章的目的。通过浏览器调试工具,我们可以清楚的看到页面资源加载的时序图:首先加载html页面,对token进行词法和语法解析,然后加载静态资源并执行相关脚本,DOM树,渲染树和CSSOM编号已构建。最后加载图片,用户看到完整的网页。虽然浏览器有自己的优化方案,但大多数情况下图片往往是最后加载的,不仅是因为图片的尺寸比较大,图片加载与否与DOM结构也有很大关系。DOM是否构建,是否在rendertree中渲染,以及其他图片加载策略都可能影响图片加载的时机。因此,在首屏时间的计算中,我们以最终首屏图片的加载时间为节点进行计算。首屏计算原则1首屏计算模块不要与业务线耦合。一般来说,首屏计算是作为一个提取出来的js脚本,单独引用。此模块尽量不向开发人员公开API。所有收集任??务都由模块完成。这句话听起来像是废话,但是还是有很多情况可能需要业务人员判断首屏的渲染时间。下面将针对这种情况给出一个实际场景:随着MVVM模型的兴起,前端异步渲染逐渐流行起来,前端编码逐渐从面向jQuery的编程转向面向Vue的编程。但是,使用Vue编写的业务代码在本地打包后只是一个bundle。此时HTML文件只是
的一个占位符,那么首屏时间计算模块应该如何呢?如何准确计算首屏时间?因此,首屏时间计算模块必须知道渲染首屏DOM结构时的时间节点,并在该节点计算首屏范围内的图片加载时间。但是如何获取首屏DOM结构渲染时的时间节点呢?这就需要业务开发人员来制定。更新vue实例的data属性后,通知首屏计算模块此时DOM界面已经渲染完成,开始计算首屏时间。在MVVM开发模式下,首屏时间的计算已经与业务代码耦合。虽然首屏时间的准确性可以得到保证,但是给开发者带来了一些相当大的判断逻辑,而这些判断往往会困扰新手。因此,我们的目标之一就是解决目前需要人工打点计算首屏时间的情况。原则2:性能和准确性之间的权衡。业界有一种方法是对canvas进行截图,通过轮询的方式比较不同时间点截图之间的某些随机像素点,判断首屏是否已经加载。虽然这种方法很科学,但估计很少有公司会采用这种方案。通过canvas截屏的操作可能对硬件要求比较高,需要额外的像素操作,所以性能肯定很差。事实上,这种场景经常发生在工程领域。工程学不像科学那样严谨。我们只需要找到给定条件的最优解。做工程也是做权衡。因此,我们也必须放弃这种比较方案。实现中再次强调首屏DOM渲染后开发者计算首屏时间是比较准确的,所以我们后面讨论的自动计算首屏时间的准确度是基于这个标准来进行对比说明的,因为自动化计算在没有人为干预的情况下肯定是准确的,这一点毋庸置疑。轮训采集方式依然是轮训,不同的是每次轮询都会进行一些操作:获取首屏的所有图片(包括IMG标签和css相关属性)并绑定首屏的onload和onerror事件图片,每次轮询绑定过的同一张图片,不会重复绑定。同一张图片不需要重复绑定事件监听,否则会混淆图片的事件处理函数与2中的每次轮询。执行打点信息统计图片加载状态,同时比较时间戳一下获取最新加载时间在具体实现中需要特别注意首屏出现同一张图片的情况。起初,作者只是简单的计算出获取第一屏图片时图片的url数组,存储重复图片的个数,并与图片的加载状态绑定。如果首屏有3张相同的图片,则在图片的onload或onerror中将加载的图片数量加3,否则最终加载的图片总数和首屏的图片总数不相等.这种实现导致逻辑非常差,实现复杂。最后通过存储图片所在的DOM对象数组,实现了更简单的图片状态判断,可读性更强。伪代码如下://totalCounter为总轮询时间//DemandCounter为指定的总轮询时间,为3000ms//imgsLoadedCount为首屏加载的图片数量//lastImageLoadedStamp为时间戳最后加载的图像functioncheckFirstScreenDomReady(){if(totalCounter>=DemandCounter){//...varstamps=Object.keys(pools),len=stamps.length,i=0,it;finalImgCount=pools[stamps[len-1]].imgLen;轮询结束=真;for(;i
=finalImgCount){self.onRecord=true;_perfQueue。_firstScreenLoadEnd=lastImageLoadedStamp;firstScreen.firstScreenLoadEnd=lastImageLoadedStamp;firstScreen.duaring=lastImageLoadedStamp-performance.timing.navigationStart;报告数据(第一个屏幕);返回;}}返回;}varimgEls=得到图像();imgEls.forEach(function(el){if(!imgLoadedHash.get(el)){varimg=newImage();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;}看门狗集合使用MutationObserverAPI监听内容框的DOM事件,判断首屏DOM结构是否完整;如果构建完成,则会监听首屏范围内的图片加载事件,看门狗在计算首屏时间时需要知道适合首屏的DOM构建完成。这就需要首屏计算模块主动插入一个点标签 ,并将业务代码放在标签里面(这一步最好放在发布阶段,用脚手架操作)。通过mutation监听.j_collector_container容器的DOM后代节点的变化。比如在observe事件处理函数中,计算.j_collector_container的高度。如果大于屏幕高度,说明首屏DOM结构已经渲染完成,开始计算首屏时间。在计算.j_collector_container的高度时,最好采用限流策略,防止短时间内多次计算容器的布局信息。这里的伪代码如下://记录首屏DOM元素的位置信息varfirstScreenDomReady=false;varcallback=function(records){if(firstScreenDomReady)返回;//这里需要节流处理for(vari=0,len=records.length;i