前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【项目】页面首屏自动化测速

【项目】页面首屏自动化测速

作者头像
神仙朱
发布2021-07-20 16:53:31
8110
发布2021-07-20 16:53:31
举报

以前写过一篇文章,专门去计算首屏时间,现在觉得那简直处理得太简单了

而且有点不太智能方便,需要手动添加代码,还要自己计算位置

今天要介绍一种我们H5用的 自动计算首屏的方法,只需要引入 js,就可以自动计算得出首屏时间

一行代码都不用写,并且精准度很高。内容很详细,所以写得有点多,但是相信我,绝对不亏

好的,本文将会按照 4 个部分来详细说明

1、基本原理

2、涉及Api 说明

3、基本处理流程

4、代码实现

5、校验算法

6、思考优化点

1.基本原理

好的,先说下这个自动测速的 主要思想

我们知道一个页面的展现,基本是由 图片 和 内容 组成的

所以我们只要知道两个时间

1、首屏内DOM 渲染的时间

2、首屏内图片加载的时间(图片没有加载之前,高度为0,所以 图片需要单独考虑)

就可以计算了

那么我们就要做下面两步

1、监听 DOM 的挂载,收集在首屏内的DOM,记录挂载时间点(表示渲染这个DOM 在 第 几 ms)

2、收集首屏内所有的 img,获取它们的 加载完成时间

那么这两个时间我们怎么计算呢?

取最大值!

首屏内有很多 img,所以我们先拿到一个 首屏 img 加载最慢的时间

and then

Math.max( 首屏DOM渲染时间,首屏 img 最大加载时间 )

然后就得出我们的

首屏时间!

好了,大概知道我们的思路之后,我们要开始详细说明了

下一节将简单介绍下 本次计算 用的 JS Api

2.涉及API介绍

本次就涉及到 两个 API

1、MutationObserver

2、performance.getEntriesByType

简单介绍一下作用(好像介绍完还是有点多),如果你懂了就直接跳过

1MutationObserver

这个 API 用于监听 DOM 树的 更改,创建时会返回一个 实例,以下简称 mo实例会提供一些方法让你自定义监听行为

new MutationObserver((mutations)=>{})

新建一个监听事例。接受一个函数作为监听回调,当有DOM变化的时候,会触发回调,并把DOM信息传入

所以可以在此时记录dom挂载的时候(刚好满足我们前面说的第一步)

它不是每挂载一个dom就触发一次回调,而是同时传入很多个dom列表所以我们并不能详细记录每一个dom的时间了,而是很多个dom记录的都是同一个时间

看下回调传入的参数格式

可以看到传入的是一个 对象数组,里面有 addedNodesremovedNodes 两个属性

里面的值监听到的 新添加 和 新移除的 dom 元素列表

我们本次计算 只用到 addedNodes 这个属性

mo.observe(target, options )

target:是要观察变化的 dom

options: 是一个对象,可以配置要观察哪些东西的变化,简单列几个

mo.disnnect()

没有参数。作用是停止监听 DOM 变化

来看一个简单的使用例子

监听整个 document 的 增删节点的变动

var observeDom = new MutationObserver(function (mutations) {

console.log('mutations', mutations);

});

observeDom.observe(document, {

childList: true,

subtree: true,

});

最后看下兼容性

反正就是不用担心,只是不支持ie10及以下

2performance.getEntriesByType(type)

筛选出当前页面加载的资源。

接受一个参数type,为了过滤出你想要的资源type 常用有 resource,mark,meassure。

type=resource 就是过滤出页面所有加载的 css,js,img, xhr 等

返回的数组可以看一下

选其中一条数据看

简单说下几个关键数据

就从这几个字段,我们就可以拿到首屏图片的耗时了

name 确定首屏的图片

responceEnd 拿到图片的加载时间

这个的兼容性同样不用担心

3.基本处理流程

上面介绍完了基本原理,以及我们需要用到的api,现在我们开始说一下基本流程了

1开启MutationObserver 监听

因为每次 MutationObserver 回调触发,会传入很多DOM,无法记录每个dom的具体时间,只能很多个dom都是记录同一个时间

然后我们只能给 每次回调都记录一次时间,以及收集此次对应的的 首屏dom

2收集DOM & 过滤DOM

用数组收集在首屏范围内的 dom 和 img(img单独收集方便处理)

怎么判断在首屏范围内?现在只要判断位置在就行,现在不在乎大小,后续在渲染完毕之后还会重新过滤一次是否在首屏内(因为此时面积不准,初始可能大小为0,渲染完毕才是真正大小,但是已经跑后面去了,不在首屏了)

把无意义的dom都过滤,减少干扰。

1、已收集的节点,过滤父级以上的节点

因为如果一个dom 已经被收集成首屏元素了,那么它的父级以上元素肯定也在首屏中,所以没必要保留

比如 script,link,br,style 等 不需要页面渲染的标签,以及 dom.nodeType!==1 的节点

3记录时间

在上面的监听回调中,我们已经记录时间了。

performance.now() 会返回一个基于当前文档生命周期的开始的时间戳

performance.now()

4定时计算

在上面我们已经做好准备工作了,那么我们什么时候开始计算呢?

当然是保证页面已经渲染完毕在进行计算啦,保证页面不再绘制,导致DOM 信息不准确

虽然 监听 window.onload 可以保证页面已经完全加载

但是并不能保证首屏显示完毕(比如有动画,或者 JS 修改 DOM 之类的)

所以我们设置一个定时器(5s),5s 之后再进行计算

5终极过滤DOM,取时间

经过上面几步,我们可以开始计算了,所谓的计算,就是把之前初步筛选出来的 首屏DOM 以及 img

在页面稳定后,重新筛选一遍,让数据更加准确

此时筛选,要求 位置在首屏中 + 有大小 + 可见

所以就调用下面这个方法

然后开始过滤拿到 所有首屏DOM 的渲染时间,以及所有首屏图片

我们过滤拿到所有的 首屏图片之后,要拿到 图片的加载时间才可以,这时候之前说的 performance.getEntriesByType 就派上用场了

好了,我们拿到了 所有首屏DOM 的渲染时间,以及 首屏图片的渲染时间

我们要怎么取舍,取最大值!!因为渲染时间肯定是取决于最慢的那一个,所以直接取最大值就好了

4.代码实现

本文代码放在仓库中

https://gitee.com/hoholove/study-code-snippet/blob/master/FIRST_SCREEN_TIME/index.js

本文参考源代码

https://github.com/Cainankun/first-screen-rendering-time/blob/master/index.js

5.算法校验

上面我们完整地说了一遍整个计算的逻辑思路,但是我们需要验证一下这个算法的正确性

看我们计算出来的时候是否正确

这次会使用 Chrome 的 Performance 面板来验证我们的数据

我们以这个页面为例,这是页面的首屏截图

首先拿到我们计算出来的首屏时间

getFirstScreenTime().then((data) =>

console.log('getFirstScreenTime', data)

);

然后在 Performance 面板中,截取从 蓝色 Loading 开始,到 绿色 Painting 结束就算是我们的首屏时间了

耗时大概959ms,几乎和我们计算的首屏时间一样了(相差的几毫秒,完全可能是手残在 面板上没有截取好)

至此证明我们的算法是完全ok 的

6.思考优化点

1时间更准确

现在只是一个基本的算法, 如果你追求更加精细,那么你可以进行多一点优化

比如如果有一张图片很大,但是只有一小部分出现在首屏中

现在是会把这张图片的加载时间算进 首屏时间的,但是按道理不合理是吧因为首屏只看到一点点,没必要把整张图片的加载时间都算进去

所以你可以优化成,根据显示的大小,按比例计算加载时间之类的

2兼容更多场景

这个算法是有缺点的

最好在页面的 head 标签中开始计算,否则有可能数据不准确

因为如果你放在 body 最后面,此时所有DOM 都挂载完了,就无法触发 MutationObserver 了

那么就无法记录 DOM 渲染的时间了。

非直出异步应用

倒是也无所谓,因为页面是根据请求异步渲染页面的

所以就算放在body 最后,执行到 首屏算法时,数据相关请求没响应,页面还没有渲染,那么此时就可以生效

直出页面中

如果计算放在 body 最后,我们是拿不到 DOM 渲染时间的

鉴于页面通常会有图片,而且通常首屏时间是 img 加载时间

所以其实可以支持多一种场景

就是直出首屏 img 多的场景,在 5s 过后,收集 首屏的 img 元素

然后 再通过 performance 去获取图片加载时间

这时我们就可以拿到首屏时间了

所以现在我们就可以覆盖以下场景

最后

鉴于本人能力有限,难免会有疏漏错误的地方,请大家多多包涵, 如果有任何描述不当的地方,欢迎后台联系本人

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 神仙朱 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档