学习
实践
活动
专区
工具
TVP
写文章
专栏首页前端杂货铺关于首屏时间采集自动化的解决方案

关于首屏时间采集自动化的解决方案

关于首屏

首屏时间是指从转向该页面到屏幕中该页面所有内容都可见时的时间。已经有太多的关于首屏时间的计算,在本文中并不重复阐述这些已经被提出或者实现的方案,而旨在探索与讨论更多的首屏自动化采集方案,扩大思考范围,你我思想之间互相碰撞往往可以激起更多的稀奇古怪的解决方案,这也正是我写这篇文章的目的。

通过浏览器调试工具,我们可以清晰的看出页面资源加载时序图:

先是html页面加载,token进行词法、语法解析后开始加载静态资源并执行相关脚本,开始构建DOM树、render树和CSSOM数,最后加载图片,用户看到完整的网页。

虽然浏览器有着各自的优化的解决方案,但是大多数情况下图片往往是最后加载完毕,这不仅仅是由于图片的大小相对较大,而且图片的加载与否与DOM结构有着很大的关系。DOM是否构建完毕,render树中是否渲染以及其他的图片加载策略有关系可能都会影响图片加载时序。因此在首屏时间的计算中,我们是以最终首屏图片的加载时间为节点计算的。

首屏计算

原则1 首屏计算模块不应该耦合业务线

一般而言,首屏计算作为一个抽离出的js脚本单独引用,这个模块尽量不暴露API给开发者使用,所有的采集端任务都由该模块完成。这句话可能听起来像一句废话,但还是有很多情况可能需要业务人员来进行首屏渲染时间的判断的,下面将针对这个情形举一个实际的场景:

随着MVVM模式的兴起,前端异步渲染逐渐流行起来,前端编码逐渐由面向jQuery编程转向为面向Vue编程。可是使用Vue编写的业务代码在本地打包后仅仅是一个bundle,此时的HTML文件中只是一个

的占位符而已,那么首屏时间计算模块该如何准确的计算首屏时间呢?因此首屏时间计算模块必须知道首屏的DOM结构渲染完毕的时间节点,在这个节点时刻进行计算首屏范围内的图片加载时间。 可是如何获取首屏DOM结构渲染完毕的时间节点呢?这就需要业务开发人员制定。在更新vue实例的data属性后,通知首屏计算模块此时DOM接口已渲染完毕,开始计算首屏时间。

MVVM开发模式下,首屏时间的计算已经耦合了业务代码,虽然可以在保证首屏时间的准确性,但却给开发者带来了一些可观判断逻辑,而这些判断往往会困扰新入职的同志们,因此我们的目标之一就是解决需要手动打点进行首屏时间计算的现状。

原则2 性能与准确性的权衡

业界有个通过canvas截屏并通过轮询对比不同时间点截屏图片之间某几个随机像素点,从而判断首屏是否加载完毕。这种方式虽然科学,但是估计没有几个公司会采用这种方案。通过canvas截屏这个操作对硬件的要求可能就比较高,而且需要进行额外的像素运算,因此性能肯定很差。其实这种场景在工程领域经常出现,工程不同于科学那般严谨,我们只需要找到给定条件的最优解即可,做工程也就是在做trade off。因此这种对比方案我们也必须摒弃。

实现

再次强调,由开发者打点首屏DOM渲染完毕进行首屏时间计算的方式是相对准确的方式,因此我们后续讨论的自动化计算首屏时间的准确性都是基于此标准进行对比说明,因为自动化计算肯定是没有人工干预准确的,这一点毫无疑问。

轮训采集大法

仍然是轮训,不同的是在每次轮询中执行一些操作:

  1. 获取首屏的所有图片(包括IMG标签与css相关属性)
  2. 绑定首屏图片的onload和onerror事件,每次轮询不会重复绑定已绑定的图片
  3. 相同图片不需重复绑定事件侦听,否则会与 2 中的每次轮询混淆
  4. 图片的事件处理函数执行打点信息并统计图片加载状态,同时比对时间戳得到最迟加载的时间

具体的实现中,需要特别注意首屏出现的相同图片的情况。笔者起初在获取首屏图片中简单计算图片的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(;i<len;i++){
            it = pools[stamps[i]];
            if(it.imgLen == finalImgCount && it.imgsLoadedCount >= 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;
}

watch dog采集

利用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<len;i++){
        // 判断首屏DOM渲染完毕的策略:
        // 判断collectWrapper元素高度是否大于首屏
        var cr = collectWrapper.getBoundingClientRect(),
        screenHeight = win.innerHeight;

        if(cr.top + cr.height >= 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://www.cnblogs.com/accordion复制
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 首屏渲染时间的计算

    最近和团队中的小伙伴一起开发一个叫 Aegis 的前端监控系统(目前仅在腾讯内部开源)。既然是前端监控系统,除了要对各种异常进行监控,还需要收集前端的各项性能,...

    腾讯IVWEB团队
  • 关于Vue首屏加载优化,说法不正确的是?

    舒克
  • 前端测试题:(解析)关于Vue首屏加载优化,说法不正确的是?

    是一套用于构建用户界面的渐进式JAVASCRIPT框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手...

    舒克
  • 淘宝是如何缩短首屏时间、降低服务器压力的?边缘计算告诉你答案!

    首先想到的是在研发过程中就对内容进行预渲染并存储起来,但是这个方案很快被 pass 了,有两个主要原因:

    童欧巴
  • 腾讯WeTest的小程序兼容测试实践之路

    作 者 朱永俊,腾讯IEG高级工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处。 作者导读 为了提升对微信小程序的测试能力, 腾讯WeTe...

    WeTest质量开放平台团队
  • 干货 | 亿万级访问量下的前端同构直出实践

    前段爱好者的知识盛宴 各位晚上好,今天进行分享的是... 来自鹅厂的dorsywang... 前端同构直出,是为了让网页加载速度更快... 然而此篇分享并不...

    用户1097444
  • 亿万级访问量下的前端同构直出实践

    兴趣部落项目自 2014 年至今,一直都是采用的是前端渲染的模式,这种模式就是页面html是一个空壳,首屏的内容需要 css 和 js 都加载完成后,请求 cg...

    王斌
  • 基于机器学习的启动耗时自动化测试方案

    当一个应用的用户越来越多,业务越来越复杂,性能问题就会突显,特别是在低端机上的用户感受尤为明显,甚至会影响到应用的用户活跃度、停留时长等重要指标,提升应用在中低...

    岛哥的质量效能笔记
  • 监控产品常见问题(第1期)

    Prometheus 监控服务(TMP) 1. TMP 和自建有什么区别吗 TMP 完全兼容开源生态,并与腾讯云监控数据打通,帮助用户快速搭建监控体系(自定义监...

    腾讯云监控团队
  • 腾讯WeTest兼容服务再次升级,支持小程序兼容

    原文链接:https://wetest.qq.com/lab/view/466.html

    WeTest质量开放平台团队
  • 腾讯WeTest兼容服务再次升级,支持小程序兼容

    WeTest 导读 小程序作为微信内能被便捷地获取和传播的工具,吸引着越来越多的开发者加入其中。无论是小游戏、零售、出行服务还是生活餐饮等,各行各业的小程序出现...

    WeTest质量开放平台团队
  • 聚焦小游戏:腾讯云 Game-Tech 技术沙龙成都站完美落幕

    据11月份阿拉丁指数微信小程序TOP100排行榜显示,小游戏类别占比超过30%,继续蝉联上榜数量最多的类别,玩家与开发者对小游戏的热度持续增加。

    腾讯游戏云
  • 技术揭秘 | 服务于130+客户的直播SDK是怎样炼成的?

    “ 导语:腾讯音视频实验室直播SDK基于QQ音视频多年在音视频技术领域的积累而搭建,广泛应用于公司内外部产品中,如坐拥大量草根网红的快手,电商类头部应用蘑菇街...

    腾讯多媒体实验室
  • 关于骨架屏与首屏渲染

    参考链接: vue-content-loader page-skeleton-webpack-plugin vue-content-loader ...

    Ewall
  • 拒绝“枯燥”设计 | 页面自动化配色的探索之路

    作者lamchen  腾讯IEG设计中心 设计师 |导语  我们在WeGame详情页设计改版探索中,无意间接触到了图片取色技术。经历一年的摸索和实践,我们在现有...

    腾讯大讲堂
  • 基于Selenium和ChromeDriver的自动化页面性能测试

    由于最近工作一直很紧张,拖了很久才在五一假期将Selenium实现自动化页面性能测试的代码实现部分补上,希望今后自己能更勤勉,多一些知识产出。 Seleni...

    全栈程序员站长
  • 腾讯前端团队是如何做web性能监控的?

    也许你有听过一个问题,你这款 web 应用性能怎么样呀?你会回答什么呢?是否会优于海量 web 应用市场呢?本文就来整理下如何进行 web 性能监控?包括我们需...

    zz_jesse
  • “直播APP源码”的系统搭建部署,主要涉及到哪些方面?

    这里主要涉及到直播平台搭建部署所用到的服务器、配置环境等。当然初期测试的话,对服务器配置方案要求并不高,通常初级服务器配置:1核CPU,2G内存,2M带宽足矣。...

    布谷鸟小刘

扫码关注腾讯云开发者

领取腾讯云代金券