前言:DOMContentLoaded
和load
最初,评价前端页面加载性能有两个指标:DOMContentLoaded
和load
事件,分别代表 DOM
树构造完成和首屏资源加载完成。
DOM
文档加载步骤:
- 解析
html
结构 - 加载外部脚本和样式表文件
- 解析并执行脚本代码
- 构造
HTML DOM
模型 (DOMContentLoaded
执行点) - 加载图片等外部文件
- 页面加载完毕 (触发
load
)
load
和 DOMContentLoaded
的不同,load
是在第六步完成之后执行,而 DOMContentLoaded
是在第四步完成之后执行。很明显 DOMContentLoaded
的执行是在 load
之前的。
当 HTML
被完全加载以及解析时,DOMContentLoaded
事件会被触发,不需要等待 css
、img
、iframe
加载完。
当整个页面及所有导入资源(比如样式表和图片)都已加载解析完成时,才会触发 load
事件。
我们来看不同 html 的 performance 截图:
- 无
css
、img
、iframe
,只有简单的一个 div 标签的:
load
事件(上图的 L)是在 DOMContentLoaded
(上图的 DCL
)事件触发之后触发的。
- 存在多个
img
标签的情况:
可以看到 DOMContentLoaded
事件还是最先执行,而 load
事件需要等待图片加载完才触发。
对于之前的页面和现代的服务端渲染(SSR,Server-Side-Render)的页面,这两个指标都可以很好地衡量首屏内容展示时间。
但对于现代复杂的单页应用,它们都是通过 JS
操作 DOM
向页面添加主要内容,对于这种场景,DOMContentLoaded
和 load
事件就不能很好地衡量首屏显示时间了。
比如我们有 render.js
、render2.js
两个文件,里边通过 js 生成了 img 标签,来看此时 DOMContentLoaded
的触发时机:
可以看到 DOMContentLoaded
事件的触发并非只针对与 html
的加载,而是需要等到导入的 js
中关于 dom
操作的部分全部执行完才会触发(因为导入的 js 资源可能存在 DOM 操作,浏览器需要等待 js 资源下载、解析完才会继续解析剩下的 HTML,生成 DOM 树)。
而页面的首次渲染可能在等待 js 资源下载的时候就已经完成(可以查看 关键路径渲染文章了解更多),那么此时使用 DOMContentLoad
或者 load
计算出来的时间就并非是页面实际的渲染时间了。
于是有了 FP
、FCP
、FMP
等概念被提出来,它们关注的不是 “加载”,而是 “渲染”,因此能更好地表现用户看到的情况。