浏览器到底是怎么渲染页面的?

三个阶段

url输入到地址栏,到页面渲染完成,总共会有三个阶段

  1. HTTP请求阶段
  2. HTTP响应阶段
  3. 浏览器渲染阶段

让我们来看看每个阶段到底发生了什么

HTTP请求阶段

  1. 在浏览器地址栏输入URL后,点击回车跳转
  2. 浏览器向服务器发起HTTP请求
  3. DNS解析
  4. TCP三次握手建立连接
  5. 建立连接后发起请求

HTTP响应阶段

  1. 服务端准备资源
  2. 服务端将资源返回给浏览器
  3. TCP四次挥手断开连接

浏览器渲染阶段

  1. 接受返回的资源
  2. 在内存中开辟出一块栈内存
  3. 解析代码(当遇到link、img、script等需要加载外部资源的文件后,开辟新的线程去加载资源文件)
  4. 解析DOM,形成DOM树,加载CSS,形成CSSOM树(DOM和CSSOM通常并行构建)
  5. 浏览器将DOM树和CSS树合并生成Render Tree(渲染树)
  6. 页面进行回流,完成基本的布局
  7. 页面进行重绘,进行样式的展示
  8. 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的最后面。

image-20220320111120678

DOMContentLoaded 与 load 的区别?

  • DOMContentLoaded事件触发时,仅当 DOM 解析完成后,不包括样式表,图片。我们前面提到CSS 加载会阻塞 Dom 的渲染和后面 js 的执行,js会阻塞 Dom 解析,所以我们可以得到结论:当文档中没有脚本时,浏览器解析完文档便能触发 DOMContentLoaded 事件。如果文档中包含脚本,则脚本会阻塞文档的解析,而脚本需要等CSSOM 构建完成才能执行。在任何情况下,DOMContentLoaded 的触发不需要等待图片等其他资源加载完成。
  • onload 事件触发时,页面上所有的 DOM,样式表,脚本,图片等资源已经加载完毕。
  • DOMContentLoaded -> load

link标签为什么放在head标签里?

我们平时编写代码时,一般都把加载css的<link>标签都放在<head>标签中,而不是像加载js文件的script标签那样放在body中最后,这是为什么呢?

  1. 放在body中:DOM Tree构建完成之后便开始构建Render Tree, 并计算布局渲染网页, 等加载解析完css之后, 开始构建CSSOM Tree, 并和DOM Tree重新构建Render Tree, 重新计算布局渲染网页。
  2. 放在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 协议 ,转载请注明出处!