FMP节点监控相对准确的计算方法是什么(FMP,开发技术)

时间:2024-05-05 19:05:54 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    如何监控节点

    监控变化

    MutationObserver

    一句话解释

    「MutationObserver 给予我们获取 DOM 渲染「切面」的能力」。

    「MDN 解释」MutationObserver 接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。

    节点标记

    有了以上能力,既可以对节点进行监听和 「标记」

    像这样

    //伪代码newMutationObserver(()=>{lettimestamp=performance.now()||(Date.now()-START_TIME),doTag(document.body,global.paintTag++);global.ptCollector.push(timestamp);});

    名词解释: - paintTag:对应 dom 的打点标记「_pi」,标记着第几次配渲染的产物。

    FMP节点监控相对准确的计算方法是什么

    • ptCollector:paintTag 对应的时间节点集合。可以用 paintTag 检索到某次渲染时刻的时间节点。

    什么时间计算?

    window.load开始计算

    为什么?

    我们认为,通常情况下,在 window 触发 load 事件的时刻,意味着主要业务的 90% 的资源和 dom 都已经准备就绪。此时算出的高权重得分的 dom 就是我们想要找的 FMP 关键节点。

    我不关心你是怎么渲染的,异步也好直出也好,殊途同归,我只关心结果

    怎么筛选元素?

    计算权重得分

    基础节点

    一个基础节点(无子节点)的权重得分计算方法:

    //伪代码constTAG_WEIGHT_MAP={SVG:2,IMG:2,CANVAS:2,VIDEO:4};node=>{letweight=TAG_WEIGHT_MAP[node.tagName],areaPercent=global.calculateShowPercent(node);letscore=width*height*weight*areaPercent;returnscore;}
    父节点

    这是一个算法我把它叫做「代父竞选」

    父节点自身的权重得分计算方法同基础节点相同,不同的是,如果其子节点的得分和大于或等于了自身的得分,将由子节点组代替父节点参与更高级的竞选,同时,子节点的权重得分和作为父节点的得分,另外,如果子节点是有孙子节点代表的,孙子节点将会同步升级。

    怎么理解呢?

    如下两种情况:

    FMP节点监控相对准确的计算方法是什么

    父元素得分=400*100=40000子元素得分和=300*60+60*60=21600父元素得分>子元素得分和

    此情况下,该组元素以 40000 的得分进入下一级竞选。参选的元素列表为父元素本身。

    数据结构如下:

    {deeplink:[{…}],elements:[{node:parent#id_search,...}],node:parent#id_search,paintIndex:1,score:40000}

    FMP节点监控相对准确的计算方法是什么

    父元素得分=400*300=120000子元素得分和=400*300+60*100=126000父元素得分<子元素得分和

    此情况下,该组元素应以 126000 的得分进入下一级竞选。参选的元素列表为子元素组,「代父竞选」。

    数据结构如下:

    {deeplink:[{…}],elements:[{node:child#id_slides_pics,...},{node:child#id_slides_index,...}],node:parent#id_slides,paintIndex:2,score:126000}

    由以上两种情况可推

    FMP节点监控相对准确的计算方法是什么

    父元素得分=400*400=160000子元素得分和=40000+126000=166000父元素得分<子元素得分和其中一个子节点由孙子节点们代表

    ==>

    {deeplink:[{…}],elements:[{node:child#id_search,...},{node:child#id_slides_pics,...},{node:child#id_slides_index,...}],node:parent#id_body,paintIndex:1,score:166000}

    所以,以下组合与拆分就不难理解了。

    排除干扰项

    在我们对 document 深度遍历计算的过程中,总会遇到一些干扰因素使我们的脚本计算出错,以下两种就是最常见的

    不可见元素

    FMP节点监控相对准确的计算方法是什么

    这种元素虽然用户无感知,但会严重影响最后的竞选结果。

    处理方案

    constisIgnoreDom=node=>{returngetStyle(node,'opacity')<0.1||getStyle(node,'visibility')==='hidden'||getStyle(node,'display')==='none'||node.children.length===0&&getStyle(node,'background-image')==='none'&&getStyle(node,'background-color')==='rgba(0,0,0,0)';}

    首先我们认为opacity < 0.1visibility === 'hidden'display === 'none'的元素为不可见元素,应忽略,另外,无子节点,且无背景无颜色的元素也归属于不可见元素,忽略。

    滚动偏移

    由于我们的脚本在 window load 后才执行,绝大情况下此时浏览器的滚动条已经发生了偏移。精选结果会发生误差。如下图:

    FMP节点监控相对准确的计算方法是什么

    此时精选结果为

    <divclass="channel"_pi="30">...</div>

    _pi 走到了30,「第 30 次渲染」,无论有多快,这个值始终会远大于实际的 FMP。

    导致「滚动偏移」的情况有两种

    • load触发前用户主动翻阅 这种情况再常见不过,用户不可能每次都等到 load 后才进行操作。而且如果存在pending的资源,load 的时间会非常迟。

    • load浏览器触发前执行了「scrollRestore (英文描述,并不存在此事件)」

    对于第二种情况,还是很好解的,因为并不是所有的浏览器都有History.scrollRestoration的特效,所以,我们只要关掉即可,但情况一我们是无论如何不能控制的。

    所以,只能另辟蹊径「划定计算区域」,且此区域应避开滚动条位置的影响。

    处理方案

    当然,我们也是有方法的,其实也挺简单。

    这得益于「document 对象的宽高是固定的,且偏移量同步于滚动条」

    constgetDomBounding=dom=>{const{x,y}=document.body.getBoundingClientRect();const{left,right,top,bottom,width,height}=dom.getBoundingClientRect();return{left:left-x,right:right-x,top:top-y,bottom:bottom-y,height,width}}

    不同元素 FMP 算法不同

    普通元素

    <DIV/><SPAN/><P/><INPUT/>这些普通元素,标注的 _pi 值索引到的渲染时刻的时间节点ptCollector还记得吗?该时间即可作为 FMP 值。

    有特殊情况,如果普通元素带有背景图片,则会升级为<IMG/>类资源元素

    资源元素

    <IMG/><VIDEO/>,该元素的 resource 的responseEnd的时间节点将作为 FMP 值

    不过,我们可以针对不同的项目对全局权重配置TAG_WEIGHT_MAP做「合理化」调整。当然也可以忽略「图片」和「视频」等资源元素资源加载时间,一切以实际项目而定

     </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
    本文:FMP节点监控相对准确的计算方法是什么的详细内容,希望对您有所帮助,信息来源于网络。
    上一篇:React Fiber树是怎么构建与更新的下一篇:

    30 人围观 / 0 条评论 ↓快速评论↓

    (必须)

    (必须,保密)

    阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18