浏览器解析HTML过程(简述)

` 提示:这里记录的流程仅从浏览器下载完html开始,至页面加载完毕结束,不涉及url解析、DNS查询、服务器建连等前置步骤。



一、什么是HTML解析过程?

        浏览器根据url从服务器下载到html资源后,将会对html的内容至上而下逐行解析后才会呈现给用户,解析过程会有下载资源(css、js、img等)、执行脚本、构建 DOM 树、渲染页面等操作,这其中有很多规则,当代码设计不合理时可能会导致解析过程冗余、页面首屏渲染时间延长、占用不必要的内存等。所以对解析过程有较全面的详细的了解,也是项目架构的基础。

二、解析顺序

1.解析<head>标签里的内容

        head标签里的内容会按照顺序逐行解析,当遇到外部引入的script时,每个都会先下载文件,下载完后进行解析。下一个script必须在上一个下载并解析完成后才能开始下载并解析,以此类推。当遇到外部引入的css时,会下载 CSS 文件的同时继续向下解析 HTML,即CSS 的下载和 HTML 的解析是并行进行的,不会阻塞 HTML 解析。但是即使 HTML 解析继续进行,浏览器在构建渲染树(Render Tree)并渲染页面时,会等待所有 CSS 文件下载和解析完成后再进行渲染。因为未完成的 CSS 可能会影响布局和样式,因此浏览器会避免在 CSS 加载完成前渲染不完整的页面。DOM 树的构建是在 HTML 解析的过程中进行的,浏览器逐行读取 HTML,边解析边构建 DOM 树,虽然DOM树的构建开始的早,但是渲染的“晚”。

当script标签有defer、async属性时,解析会有所变化,具体如下
(1).从改变脚本处理方式上看,async 属性与 defer 类似。它们两者也都只适用于外部脚本,都会告诉浏览器立即开始下载,并且同时向下继续解析,不会阻塞解析。
(2).在script元素上设置 async 属性时,浏览器立即下载,下载结束后立即执行。
(3).在script元素上设置 defer 属性时,脚本会被延迟到整个页面都解析完毕后再运行,相当于告诉浏览器立即下载,但延迟执行。
(4).当有多个async属性的script元素时,标记为 async 的脚本并不保证能按照它们出现的次序执行。
(5).当有多个defer属性的script元素时,HTML5 规范要求脚本应该按照它们出现的顺序执行,因此第一个推迟的脚本会在第二个推迟的脚本之前执行,而且两者都会在 DOMContentLoaded 事件之前执行。不过在实际当中,推迟执行的脚本不一定总会按顺序执行或者在 DOMContentLoaded事件之前执行,因此最好只包含一个这样的脚本。

        当<head>中需要引入外部js文件时,可通过link的方式预加载,这样可以加快后续 <script> 标签中相同文件的加载速度。这种方法可以避免阻塞页面的渲染,尤其是在需要处理较大的 JavaScript 文件时。

<!-- 使用 script 标签引入并执行 JavaScript 文件 -->
<script src="main.js" defer></script>

<!-- 使用 link 标签预加载 JavaScript 文件,提升后续加载速度 -->
<link rel="preload" href="main.js" as="script">
<!-- 仍然需要 script 标签来执行 -->
<script src="main.js" defer></script>

2.解析<body>标签里的内容

规则同上,逐行解析,继续构建DOM树,下载、执行、解析引入资源。

3.解析完毕后

1.DOM树构建完毕:DOM 树的构建完成的时机通常是在 HTML 文件完全解析后,也就是当浏览器遇到文档中的最后一个标签(通常是 )时,浏览器才认为 DOM 树构建完毕。
2.构建渲染树:DOM树构建完毕后,浏览器就会根据 DOM 树和外部的 CSS 样式来构建渲染树。渲染树是浏览器最终用来绘制页面的结构,它包含了所有可见元素的样式、位置和大小。
3.布局:浏览器根据渲染树来确定各个元素的具体位置和大小。这一过程称为布局或重排。浏览器会遍历渲染树并计算每个元素的几何信息。
4.绘制:一旦完成布局,浏览器开始将渲染树中的每个节点绘制到屏幕上。这个过程称为绘制或重绘。绘制包括填充背景、文本、边框和其他视觉效果。
5.合成:在一些现代浏览器中,页面的不同层(如背景、文本、图像等)会被分成多个图层进行渲染。每个图层都会单独绘制,然后通过合成过程合成到最终的屏幕上。
6.执行:如果页面中包含 <script> 标签,浏览器会在解析 HTML 的过程中遇到这些标签时执行 JavaScript 代码。现代浏览器通常会在 HTML 的解析过程中并行加载和执行 JavaScript,但有时也会根据 async 或 defer 属性控制脚本执行顺序。
7.事件绑定: 在浏览器加载和渲染页面的过程中,JavaScript 会通过事件监听器来绑定用户交互事件(如点击、滚动等)。这些事件会触发相应的处理函数,改变页面的内容或样式。
8.持续渲染:一旦页面开始渲染,浏览器会持续监视页面的状态,例如用户滚动、窗口大小调整等,并根据需要重新布局和重绘页面。

注:页面首屏是在浏览器解析完html、构建完DOM树和CSSOM树后布局、绘制、合成后展示的,在此之前浏览器窗口完全空白,而且浏览器又是顺序逐行解析的,所以当html中需要下载和解析的内容过多时,首屏加载时间会大受影响。为解决这个问题,尽量不要使用内联的JS代码,确实需要引入时注意引入的位置并且考虑使用异步和预加载。这样可以确保浏览器优先解析和渲染页面内容,而不会因为脚本加载和执行而阻塞渲染。


tip

浏览器渲染 HTML 的过程虽然复杂但有规律,掌握渲染规律不仅有助于优化性能,还能深入理解前端开发的流程。这是我阶段性的一些简单记录,后续会在有时间时进一步优化和完善内容。如果其中有问题或不准确的地方,欢迎指正。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐