浏览器到底是怎么渲染页面的?
三个阶段
当url输入到地址栏,到页面渲染完成,总共会有三个阶段
- HTTP请求阶段
- HTTP响应阶段
- 浏览器渲染阶段
让我们来看看每个阶段到底发生了什么
HTTP请求阶段
- 在浏览器地址栏输入URL后,点击回车跳转
- 浏览器向服务器发起HTTP请求
- DNS解析
- TCP三次握手建立连接
- 建立连接后发起请求
HTTP响应阶段
- 服务端准备资源
- 服务端将资源返回给浏览器
- TCP四次挥手断开连接
浏览器渲染阶段
- 接受返回的资源
- 在内存中开辟出一块栈内存
- 解析代码(当遇到link、img、script等需要加载外部资源的文件后,开辟新的线程去加载资源文件)
- 解析DOM,形成DOM树,加载CSS,形成CSSOM树(DOM和CSSOM通常并行构建)
- 浏览器将DOM树和CSS树合并生成Render Tree(渲染树)
- 页面进行回流,完成基本的布局
- 页面进行重绘,进行样式的展示
- GPU渲染整个页面
HTML与CSS的解析主要由GUI渲染线程负责,js由Javascript引擎线程负责,由于js可以操作dom元素和样式,所以如果GUI线程和Javascript引擎线程一起并行会造成冲突。因此GUI渲染线程与Javascript引擎线程是互斥的。
若解析dom时遇到script需要执行js,则会阻塞js的执行,直到css样式表加载完成
若解析dom时css已加载完毕,遇到script需要执行js,则会停止解析dom,先执行js。因此,我们最好把script放在body的最后面。
DOMContentLoaded 与 load 的区别?
- 当
DOMContentLoaded
事件触发时,仅当DOM 解析
完成后,不包括样式表,图片。我们前面提到CSS 加载
会阻塞Dom 的渲染
和后面js 的执行
,js
会阻塞Dom 解析
,所以我们可以得到结论:当文档中没有脚本时,浏览器解析完文档便能触发DOMContentLoaded
事件。如果文档中包含脚本,则脚本会阻塞文档的解析,而脚本需要等CSSOM 构建完成
才能执行。在任何情况下,DOMContentLoaded
的触发不需要等待图片等其他资源加载完成。 - 当
onload
事件触发时,页面上所有的 DOM,样式表,脚本,图片等资源已经加载完毕。 DOMContentLoaded
->load
。
link标签为什么放在head标签里?
我们平时编写代码时,一般都把加载css的<link>
标签都放在<head>
标签中,而不是像加载js文件的script
标签那样放在body
中最后,这是为什么呢?
- 放在body中:DOM Tree构建完成之后便开始构建Render Tree, 并计算布局渲染网页, 等加载解析完css之后, 开始构建CSSOM Tree, 并和DOM Tree重新构建Render Tree, 重新计算布局渲染网页。
- 放在head中:先加载css, 之后解析css构建CSSOM Tree, 于此同时构建DOMTree, CSSOM Tree和DOM Tree都构建完毕之后开始构建Render Tree, 计算布局渲染网页。
对比两者, css放在<head>
标签中比css放在body标签尾部少了一次构建Render Tree, 一次计算布局和一次渲染网页, 因此性能会更好; 并且css放在body标签尾部时会在网页中短暂出现”裸奔”的HTML, 这不利于用户体验。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!