深入理解DOM树的加载过程

本文整理介绍有关DOM的加载过程。DOM树加载从用户在地址栏输入一个有效URL并回车开始,到整个页面请求渲染加载完成并展现出来截止,在这个过程中发生的诸多细节,将在下文中整理介绍。

简要流程

从用户在地址栏完成地址输入到页面展现的简要流程如下:

  • 浏览器将URL交给DNS域名解析器进行解析,得到目标的IP地址,然后向服务建立TCP连接,发送HTTP请求;
  • 服务器根据浏览器的请求地址和数据在后台进行处理,返回页面信息给浏览器;
  • 浏览器接收页面数据,包括 jshtmlcss图片字体 等信息;
  • 浏览器对页面的 html 和 css 构建DOM树和渲染树,并渲染页面,展示到前台;
  • 浏览器解析接收到的 js 文件,注册响应的事件并绑定到DOM节点。

详细流程

DOM加载的详细流程可以设计 DNS域名解析、DNS缓存、资源缓存、DOM树构建,渲染树构建,和事件绑定等,可概括为:

  • 用户在浏览器输地址栏输入地址后回车,发起请求;
  • 浏览器通过URL识别本地缓存,查看目标资源是否在本地缓存且有效;
    • 如果目标资源没有缓存,则发起缓存,见后续步骤;
    • 如果资源以及缓存,则坚持缓存是否过期。如果没有过期,则使用缓存;如果资源过期,则发起请求,从服务器对资源进行重新验证;
    • 缓存涉及到两个HTTP头,ExpiresCatch-Control
    • HTTP 1.0 提供 Expires ,其值为一个绝对时间,表示缓存的过期时间;
    • HTTP 1.1 增加了 Catch-Control,通过 max-age= 来设置缓存最大保留时间
  • 浏览器得到数据后,开始构建DOM树,以 document 为根节点,根据 html 标签依次在根节点逐层注册新节点;
    • 遇到 link 标签引用 css 时,并行下载 css 文件;
    • 遇到 style 标签时,解析标签内的样式表;
    • 遇到 script 标签内有 js 代码时,开始执行 js 代码,此时 DOM 树的构建会被暂停,直到 js 解析完成;
    • 如果遇到 script 标签时引用外部的 js 文件,则并行下载 js 文件,这里包含两种情况;
    • 如果 script 标签标记了 async 属性,则并行下载 js 文件,下载完成后立即执行;
    • 如果 script 标签标记了 defer 属性,则并行下载 js 文件,并按照 defer 的顺序先后执行;
  • 浏览器在 document 上触发 DOMContentLoaded 事件;
  • 此时整个文档解析渲染完成,但可能一些静态资源还在下载,如图片等,这些资源文件会在下载完后载入,这些异步的载入不会影响到 document.readState 。
  • 当 document.readState 为 complete 时,表示DOM树构建完毕,此时在 window 上触发 load 事件,可通过 window.onload 定义该事件的监听

引申:script 标签的 async 和 defer 属性

整个成中有关 script 标签异步载入 Js 代码需要注意两个属性,即 asyncdefer ,这两个属性都表示异步载入 js 代码,即下载 js 时不会影响 DOM 树构建,但需要区别这两个属性的含义。这里整理如下:

  • async,异步下载,尽快执行,执行时可以访问到其 script 标签以上的节点;
  • defer,异步下载,延迟到整个页面解析完毕后并按顺序执行,执行时间为文档渲染完毕后,但在触发 DOMContentLoaded 事件之前,所以其标签所引用的代码可以访问整个页面节点。

引申:页面缓存机制

引申:document.readState 状态值

readyState 属性返回当前文档的状态,有下列枚举值:

  • uninitialized:还未开始载入;
  • loading: 载入中;
  • interactive: 已加载,文档与用户可以开始交互;
  • complete: 载入完成

使用 JavaScript 进行编程时,可以在 document 对象上监听 readystatechange 事件,以便获取文档状态,一般当 readyState 属性值变为 complete 后开始触发 windowload 事件。

// 解析中
console.log(document.readyState);       // loading
// 载入完成后触发 window 的 load 事件
window.onload = function () {
    console.log(document.readyState);   // complete
}

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注