Skip to main content

如何展示页面的

从一道经典的面试题入手:从用户输入 URL 到页面展示,这中间都发生了什么?

渲染过程

主要分为3个阶段

  1. HTTP 请求阶段
    1. 浏览器首先检查本地缓存,如果存在相应资源的缓存并且未过期,可以跳过请求服务器的步骤
    2. 如果缓存无效,浏览器将根据输入的 URL 解析出协议(通常是 HTTP 和 HTTPS),域名(例如 www.example.com),端口号(HTTP 默认是80,HTTPS 默认是 443)
    3. 浏览器向域名解析服务器发出 DNS 查询请求,将域名解析为服务器的 IP 地址
    4. 拿到 IP 地址,浏览器将与服务器建立 TCP 连接,这个过程涉及3次握手
    5. 浏览器发送 HTTP 请求
  2. HTTP 响应阶段
    1. 服务器接收到请求后,会根据请求的 URL 和参数来查找或生成响应的资源
    2. 服务器发送 HTTP 响应
  3. 浏览器渲染阶段
    1. 浏览器解析响应体的内容,通常是 HTML 数据
    2. 浏览器创建 DOM Tree(DOM Tree 是文档对象模型树,是浏览器对页面的内部表示)
    3. 浏览器加载外部资源,例如 CSS、JS、媒体文件
    4. 浏览器解析 CSS 并计算每个 DOM 节点的样式,同时创建 CSSOM Tree(CSSOM Tree 是 CSS 对象模型树,即使不提供 CSS,浏览器也有默认样式)
    5. 浏览器遍历 DOM Tree 并创建 Layout Tree(Layout Tree 是布局树)
    6. 浏览器遍历 Layout Tree 并创建 paint records(paint records 是对绘画过程的记录,通常顺序是先背景,再文字,后矩形)
    7. 浏览器遍历 Layout Tree 并创建 Layer Tree(Layer Tree 是层树)
    8. 浏览器将 Layer Tree 提交给合成器线程 Compositor,合成器线程对每个Layer 进行栅格化,创建合成器帧
    9. 浏览器将合成器帧发送到 GPU 进程 以在屏幕上显示
    10. JS 代码解析和执行的过程可能会修改 DOM Tree 或 CSSOM Tree,这可能触发回流 Reflow重绘 Repaint,导致浏览器重新计算布局和重新绘制

JavaScript 可以阻止解析

当 HTML 解析器发现一个 <script> 标签时,它会暂停对HTML文档的解析,并加载、解析和执行 JavaScript 代码。因为 JavaScript 可以使用诸如 document.write() 之类的功能来改变文档的结构,从而改变整个 DOM 结构,因此 HTML 解析器必须等待 JavaScript 运行完毕,然后才能恢复对 HTML 文档的解析。为了提高页面加载性能,通常把 <script> 标签放在 <body> 标签的底部。

如果不希望阻塞页面加载,也可以使用 <script> 标签的 async 和 defer 属性。

  • async 表示异步加载和执行,不会阻塞页面的呈现
  • defer 表示将在 HTML 文档解析完成后执行

参考文章

https://developer.chrome.com/blog/inside-browser-part1/