浏览器从服务器获取到 HTML 文档后,HTML 解释器开始对 HTML 自上而下解析,构建 DOM Tree(DOM 树)。CSS 解释器解析 CSS,构建 CSS Rule Tree(CSS 规则树)。文档解析完成后,将 CSS Rule Tree 附加到 DOM Tree 生成 Render Tree(渲染树)。而后,Layout(布局)会从渲染树的根节点开始遍历,输出渲染树上每个节点在页面上的具体大小和位置。
为了更好的用户体验,渲染引擎会尽可能早地将内容呈现到屏幕上,并不会等到所有的 HTML 都解析完成之后再去构建和布局渲染树,而是逐步解析并显示对应内容。
在解析 HTML 过程中,如果遇到引入外部样式或脚本(非 defer 或 async)时,会暂停文档解析,并创建新的网络连接来下载样式文件和脚本文件。样式文件下载完成后,构建 CSS 规则树 CSS Rule DOM,而脚本文件下载完成后,会被 JavaScript 引擎解释并执行。
渲染优化:
如果 CSS 样式声明放在文档靠前位置,如 <head> 标签中,则 CSS Rule Tree 会先于 DOM Tree 完成构建,之后浏览器就可以边构建 DOM Tree 边完成渲染;反之,如果将 CSS 样式声明放在文档靠后位置,如 < body/> 标签前,而 Render Tree 只有在 CSS Rule Tree 构建完成后才会被生成,浏览器将页面渲染出来的速度就变慢了,这样给用户一个不好的体验。
通常来说,JavaScript 主要是用户交互的逻辑,并不要求在页面初次展现前处理,而引入外部脚本文件通过流量传输不可避免地阻塞了浏览器的渲染过程,因此,JavaScript 文件的引入最好是放到文档靠后的位置,如 < body/> 标签前,这样有利于将页面更快地展示出来给用户。