图3.12 浏览器显示网页的流程
可以将DOM树理解为结构树或内容树。浏览器解析HTML文档,并将各元素标签逐个转换成DOM节点,即把HTML文档中的标签转换成一个结构树。这个解析和构造过程是流式的,浏览器每获取HTML的一部分,便会立刻对其进行解析。以3.1.2小节中的网页为例,其DOM树如图3.13所示,其中省略了元素的属性。
图3.13 DOM树
呈现树是网页显示部分的数据结构。在构造DOM树的同时,也会解析外部CSS文件及元素标签中的样式设置,浏览器会构造一个与CSS样式对应的CSSOM树。浏览器会利用CSSOM树中的视觉属性(如颜色和尺寸)和DOM树对应的元素构造另一个结构——呈现树。呈现树和DOM树相对应,可以简单地理解为在DOM树的节点上添加视觉属性。但是呈现树与DOM树并非一一对应,呈现树只记录在浏览器上可显示的部分,一些非可视化的元素(如<head></head>)和一些被隐藏的元素是不会被记录在呈现树上的。仍以3.1.2小节中的网页为例,其呈现树如图3.14所示。
图3.14 呈现树
呈现树构造完毕之后,进入布局处理阶段。布局处理阶段主要是根据呈现树和浏览器窗口的大小计算出每一个节点出现在屏幕上的确切坐标。最后进行绘制,即把网页描画出来。
浏览器显示网页是渐进的过程,上文提到的流程并不是一次完成的。浏览器会尽快将内容显示在屏幕上,而不是等到整个HTML文档解析完毕才开始构建呈现树和设置布局。
在不断接收和处理网络资源的同时,浏览器会不断解析并显示内容。在以上过程中并没有提及JavaScript文件的作用。浏览器有专门的JavaScript解析器处理JavaScript文件。JavaScript解析器中会有一些预编译的流程,不过这是内部行为,我们不必过于关心。
JavaScript脚本可以响应网页事件(如单击和拖动等),调用浏览器的一些功能(如全屏等),以及与远端服务器通信(请求数据)等。JavaScript脚本对于网页显示而言,其最大的作用是可以修改HTML内容(即可以改变DOM树,一般来说,JavaScript脚本修改HTML内容的操作也被称为DOM操作),HTML内容发生变化后,浏览器会自动进行网页的重排和重绘,从而显示新的网页。例如3.1.2小节中的网页,当单击按钮后,JavaScript脚本会自动改变网页的文字内容。
以上是前端网页的工作原理。但是还有一个问题没说清楚。在3.1.2小节中为什么要把JavaScript文件的引用放在<body></body>的后面,而将CSS文件的引用放在<head></head>中呢?
这是因为,浏览器虽然对HTML文件是流式处理的,但是JavaScript文件可能会修改HTML的内容,即可能会影响DOM树的结构,从而影响呈现树的构造及后续的流程,所以当浏览器处理到<script></script>标签时,会停止对HTML文件的解析,先加载并处理完JavaScript文件后再继续解析HTML文件。在一般情况下,JavaScript脚本只在响应事件(如单击)后才会操作HTML元素,因此把JavaScript的引用放在<body></body>的后面有利于DOM树的构建,从而有利于网页尽早显示出来。再者,因为JavaScript脚本可能会操作DOM树,如果放在开头,则可能会导致由于被操作的元素还没被构造出来而发生错误。
而CSS文件由于不影响DOM树的构造,因此当浏览器处理到<link></link>标签时会继续往下解析。因为CSS文件会影响呈现树的构造,所以会暂停呈现树的构造,直到CSS文件下载结束并解析完成。把CSS文件放在<head></head>中,可以让浏览器尽早加载CSS文件,这样有利于呈现树的构造,从而有利于网页尽早显示。
以3.1.2小节中的网页为例,整个网页解析的渐进过程如图3.15所示。其中,黑色粗线为构造过程,这里只体现了DOM树的构造和呈现树的构造这两部分,而省略了布局处理和绘制这两个浏览器的自发行为。
图3.15 网页构造的全过程
在不同的浏览器中,具体构造DOM树和呈现树的暂停点和开始点是有所区别的,不过大体上仍然如图3.15所示。
本文给大家讲解的内容是大型网站架构的技术细节:前端架构,前端的工作原理- 下篇文章给大家讲解的内容是大型网站架构的技术细节:前端架构,前端架构需要解决的问题
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!