关于首屏时候收集自动化的解决方案

关于首屏

首屏时候是指从转向该页面到屏幕中该页面一切内容都可见时的时候。已有太多的关于首屏时候的盘算,在本文中并不反复论述这些已被提出或许完成的计划,而旨在探究与议论更多的首屏自动化收集计划,扩展思索局限,你我头脑之间相互碰撞每每能够激起更多的八怪七喇的处置惩罚计划,这也恰是我写这篇文章的目的。

经由过程浏览器调试东西,我们能够清楚的看出页面资本加载时序图:

先是html页面加载,token举行词法、语法剖析后最先加载静态资本并实行相干剧本,最先构建DOM树、render树和CSSOM数,末了加载图片,用户看到完全的网页。

虽然浏览器有着各自的优化的处置惩罚计划,然则大多数状况下图片每每是末了加载终了,这不仅仅是由于图片的大小相对较大,而且图片的加载与否与DOM构造有着很大的关联。DOM是不是构建终了,render树中是不是衬着以及其他的图片加载战略有关联能够都邑影响图片加载时序。因而在首屏时候的盘算中,我们是以终究首屏图片的加载时候为节点盘算的。

首屏盘算

准绳1 首屏盘算模块不应该耦合营业线

一般而言,首屏盘算作为一个抽离出的js剧本零丁援用,这个模块只管不暴露API给开辟者运用,一切的收集端使命都由该模块完成。这句话能够听起来像一句空话,但照样有许多状况能够须要营业人员来举行首屏衬着时候的推断的,下面将针对这个情况举一个现实的场景:

跟着MVVM形式的鼓起,前端异步衬着逐步流行起来,前端编码逐步由面向jQuery编程转向为面向Vue编程。但是运用Vue编写的营业代码在当地打包后仅仅是一个bundle,此时的HTML文件中只是一个 <div id=”app”></div> 的占位符罢了,那末首屏时候盘算模块该怎样正确的盘算首屏时候呢?因而首屏时候盘算模块必需晓得首屏的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构建终了。这须要首屏盘算模块主动插进去一个办理标签 <div class=”j_collector_container”></div>,将营业代码安排在标签内部(这个步骤最好放在宣布阶段,由脚手架操纵)。经由过程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个异常庞杂的子组件,获得以下效果:

《关于首屏时候收集自动化的解决方案》

《关于首屏时候收集自动化的解决方案》

《关于首屏时候收集自动化的解决方案》

效果也相符我们的预期。

    原文作者:RoyalRover
    原文地址: https://segmentfault.com/a/1190000013016763
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞