当前位置: 首页 > Web前端 > HTML

你的网页有多快——从DOMReady到ElementTiming

时间:2023-03-27 23:51:31 HTML

一些废话我们都知道你需要一个标题才能写一篇文章。虽然我们这些搞代码的人一般都喜欢开门见山,但是由于文体的限制和发表载体的要求,有时候还是得想个标题。而起一个标题不亚于起一个函数名或变量名。光是这篇文章,我就有好几个草稿标题,比如:《页面加载指标演进之路》、《Element Timing:一种全新的页面速度指标》、《如何最准确地测量网页加载速度》、《新前端下的页面加载速度》,甚至是《Element Timing In Action》、《三分钟学会测量页面速度》。最后综合考虑读者的承受能力,编辑的意见,还有最重要的:本人文笔薄弱,选择了这么一个很火的,既不会一看就认为是垃圾,也不会被pick被别人。出来仔细挑剔标题。好了废话不多说,直入正题。在远古的DOMReady时代(指10+年前的jQuery时代),我们对网页的开发还仅限于编写静态页面结构,使用JS脚本直接操作DOM,增删一些额外的页面元素。这时候DOMReady就基本可以满足计算页面加载完成时间的需求了。DOMReady(DOM事件中的DOMContentLoaded)表示页面文档完全加载和解析,一般包括HTML文档解析、DOM树的创建、外部链接脚本的加载、外部链脚本的执行和内联脚本的执行,无需等待样式文件、图像文件和子框架页面加载。一般在页面头部放一个时间戳,然后在jQuery的domReady事件中放一个时间戳,我们就可以计算出DOMReady的大概耗时。NavigationTiming在中世纪(指大约10-5年前的Ajax时代),网页的交互形式变得更加多样化。以Gmail为首的富Web应用在极大提升用户体验的同时,也带来了细粒度的网页加载时间记录。需求来了。因此,从2010年开始,WebPerformanceWorkingGroup引入了大量针对Web的时间信息记录,可以通过window对象的performance属性获取。这后来被称为导航计时。NavigationTiming接口提供的数据大致如图所示:基本涵盖了从网页开始网络请求到页面完全加载、资源执行、DOM节点初始化的时间。我们可以直接使用performance.timing轻松获取这些时间来帮助分析页面的加载时间。FP、FCP和LCP在远古时期(指大约5-2年前的React时代),由于各种前端框架(React、Vue等)的兴起,以及Webpack的出现,一款前端搭建神器,让开发网页的难度迅速下降,同时复杂度也暴涨。前端密集型应用程序很受欢迎,在页面上加载脚本所需的时间正在迅速变长。许多网站在体验上采用渐进式加载策略来解决等待脚本执行时白屏时间过长的问题。因此,ProgressiveWebRendering指标诞生了。渐进式网页指标一般有这些:首绘(FP):全称FirstPaint,标记浏览器渲染任何与导航前屏幕内容在视觉上不同的内容的时间点首绘(FCP):全称FirstContentfulPaint,它标记浏览器从DOM呈现第一个内容的点,它可以是文本、图像、SVG甚至元素。FirstEffectivePaint(FMP):全称FirstMeaningfulPaint,标记页面主要内容绘制的时间点,比如视频应用的视频组件、天气应用的天气信息、新闻应用程序中的新闻项目。Maximumcontentdrawing(LCP):全称LargestContentfulPaint,标记可见区域中“内容”最大的可见元素开始在屏幕上绘制的时间点。其中,FMP由于依赖算法猜测有效元素,已基本被抛弃。这些指标的视觉意义可以参考下面两张图:由于复杂页面中往往有很多元素,FCP观察到的元素可能只是一个loading标签或者是一个意义不大的侧边栏,所以对于真实用户来说,并不代表的“首屏时间”页面。相反,在一些逻辑复杂的页面中,由于JS代码的执行时间较长,或者依赖于很多后端接口来渲染页面,页面中最重要数据的显示时间往往比由页面OnLoadEvent触发的时间,对于用户来说最直观的“首屏时间”往往就是LCP的时间。这也是为什么现在很多前端页面性能工具都把LCP作为一个重要的参考指标。在ElementTiming的现代时代(指1-0年前的微前端时代),LCP的计算逻辑由浏览器给出。在不同的页面上,浏览器考虑的最大可见元素不一定是我们业务中最大的可见元素。真正重要的内容。而在微前端盛行的现代,不仅同一个应用的不同页面采用单页模式,甚至不同子应用的加载也可能由哈希路由来驱动。对于这种单页应用,以上指标均不能满足主框架加载完成后切换不同页面时的重新计算。那么我们是否只能完全依靠业务开发本身在代码中主动管理和报告加载时间呢?不一定如此。让我们看一下新的W3C草案,即ElementTimingAPI:https://wicg.github.io/element-timing/。虽然这个API还处于草案阶段,但是Chrome和Edge浏览器都已经在新版本中支持了:页面,相比LCP,我们可以自己定义关键元素,这是ElementTiming最大的魅力所在。ElementTiming支持以下元素:elementinelementin

constobserver=newPerformanceObserver((list)=>{letentries=list.getEntries().forEach(function(entry){console.log(entry);});});observer.observe({entryTypes:["element"]});//输出条目内容://{//持续时间:0//元素:p.aimake-site-name//entryType:"element"//id:""//identifier:"text-id"//intersectionRect:DOMRectReadOnly{x:236,y:130,width:144,height:28,top:130,…}//loadTime:0//name:"text-paint"//naturalHeight:0//naturalWidth:0//renderTime:10850.899999976158//startTime:10850.899999976158//url:""//}但需要注意的是,并不是所有的文本节点都可以通过添加elementtiming="ElementTimingAPI来识别,WICG的解释中有一个注释:我们说a文本节点属于最近的b节点的锁定级元素祖先。这意味着一个元素可以有0个或多个关联的文本节点。如果至少有一个文本节点属于并且至少被绘制过一次,我们就说该元素是文本绘制的。因此,一个元素的文本渲染时间戳就是它变成_text-painted_的时间。让文本节点的文本矩形成为该节点在视口中的显示矩形。我们将一个元素的文本矩形定义为包含属于该元素的所有文本节点的文本矩形的几何并集的最小矩形。难以阅读,但其实它想说明的是只有满足以下条件的文本节点才能被记录:必须是块级元素:如

等,也就是说,内联元素比如单个元素,即使加上elementtiming=""属性,也不会被记录为直接子节点一个节点必须包含一个或多个文本节点:比如纯文本、等,

等块级元素不算,等图片不算。举几个例子来理解:

1

2

span1
1

2

3

4
b1i1h1section1添加自定义elementtiming属性后,当标记的图片或文本节点真正被渲染时,浏览器会记录因此,在不同的应用程序,我们可以让开发者直接给可以标记首屏的元素加上这个属性,采集脚本可以通过监听PerformanceObserver来采集元素绘制的时间点(renderTime)。通过使用ElementTimingAPI,我们可以更准确地记录每个应用程序、页面甚至功能模块的加载时间。这是页面加载时间最现代、最前沿的解决方案,其余的最终将被埋没在历史的尘埃中!开玩笑和其他废话。代代英才出,各领风骚数百年。一般来说,结局不如片名重要,不用费心去想N个结局。简单总结一下:不管前端发展到什么地步,Timing标准永远赶不上你!希望有读者能得到一点启发,写一个包含ElementTiming指标的性能库,让我们受益。毕竟我比较懒,以上都是自己YY的用法。提前致谢。作者:ES2049|匿名文章可以随意转载,但请保留原文链接。如果你有热情,非常欢迎你加入ES2049Studio。请将简历发送至caijun.hcj@alibaba-inc.com。