小言_互联网的博客

浏览器-DOM树

226人阅读  评论(0)
前言:

在渲染流水线中直接或者间接地依赖于 DOM 结构,本文按着网络数据流路径来介绍 DOM 树是如何进行构建的。

节点(Node):

节点(Node)原本是网络术语,表示网络中的连接点。一个网络是由一些节点构成的集合。节点作为 DOM 树结构中的连接点,最终构成了完整的 DOM 树结构。

常见节点类型:

除了常见的节点还有其他的一些节点类型。


DOM:

从网络传给渲染引擎的 HTML 文件字节流是无法直接被渲染引擎理解的,所以要将其转化为渲染引擎能够理解的内部结构,这个结构就是 DOM。

文档对象模型 (DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。

DOM的作用:

  • 从页面的视角来看,DOM 是生成页面的基础数据结构。
  • 从 JavaScript 脚本视角来看,DOM 提供给 JavaScript 脚本操作的接口,通过这套接口,JavaScript 可以对 DOM 结构进行访问,从而改变文档的结构、样式和内容。
  • 从安全视角来看,DOM 是一道安全防护线,一些不安全的内容在 DOM 解析阶段就被拒之门外了。

DOM 中的 M 表示 Model(模型),也可以用来表示 DOM 节点树结构中节点之间的关系。

DOM 节点树结构的关系:

  • 父级与子级:
    将 HTML 页面中某一个元素作为父级的话,那包含在该元素内的第一层所有元素都可以称为该元素的子级。
  • 祖先与后代:
    将 HTML 页面中某一个元素作为祖先的话,那包含在该元素内的所有元素(除子级之外的)都可以称为该元素的后代。
  • 兄弟关系:
    具有相同父级元素的两个或几个元素之间就是兄弟关系。

DOM树:

在渲染引擎内部,有一个叫HTML 解析器(HTMLParser)的模块,它的职责就是负责将 HTML 字节流转换解析为 DOM树 结构。

通过节点概念,我们可以将原本的 DOM 树结构改成 DOM 节点树结构进行表示:

DOM树的构建过程:

网络进程接收到响应头之后,会根据响应头中的 content-type 字段来判断文件的类型,比如 content-type 的值是“text/html”,那么浏览器就会判断这是一个 HTML 类型的文件,然后为该请求选择或者创建一个渲染进程。渲染进程准备好之后,网络进程和渲染进程之间会建立一个共享数据的管道,网络进程接收到数据后就往这个管道里面放,而渲染进程则从管道的另外一端不断地读取数据,并同时将读取的数据“喂”给 HTML 解析器。你可以把这个管道想象成一个“水管”,网络进程接收到的字节流像水一样倒进这个“水管”,而“水管”的另外一端是渲染进程的 HTML 解析器,它会动态接收字节流,并将其解析为 DOM。


字节流转换为 DOM 的三个阶段:

  • 通过分词器将字节流转换为 Token。
    Token分为Tag Token 和文本 Token,Tag Token 又分 StartTag 和 EndTag。
  • 将 Token 解析为 DOM 节点。
    如果HTML 解析器维护了一个Token 栈结构,压入到栈中的是StartTag Token,HTML 解析器会为该 Token 创建一个 DOM 节点,然后将该节点加入到 DOM 树中,它的父节点就是栈中相邻的那个元素生成的节点。
  • 将 DOM 节点添加到 DOM 树中。
    如果分词器解析出来是文本 Token,那么会生成一个文本节点,然后将该节点加入到 DOM 树中,文本 Token 是不需要压入到栈中,它的父节点就是当前栈顶 Token 所对应的 DOM 节点。
    如果分词器解析出来的是EndTag 标签,比如是 EndTag div,HTML 解析器会查看 Token 栈顶的元素是否是 StarTag div,如果是,就将 StartTag div 从栈中弹出,表示该 div 元素解析完成。

影响 DOM 生成的因素:

  • 解析流程中解析到script标签时,渲染引擎判断这是一段脚本,此时 HTML 解析器就会暂停 DOM 的解析,因为 JavaScript 可能要修改当前已经生成的 DOM 结构。当脚本执行完成之后,HTML 解析器恢复解析过程,继续解析后续的内容,直至生成最终的 DOM。
  • 先解析 JavaScript 语句之上所有的 CSS 样式。如果代码里引用了外部的 CSS 文件,那么在执行 JavaScript 之前,还需要等待外部的 CSS 文件下载完成,并解析生成 CSSOM 对象之后,才能执行 JavaScript 脚本。

结论:
渲染过程中JavaScript 会阻塞 DOM 生成,而样式文件又会阻塞 JavaScript 的执行,所以在实际的工程中需要重点关注 JavaScript 文件和样式表文件,使用得当才能提高页面的性能!

优化方案:

  • 预解析操作,当渲染引擎收到字节流之后,会开启一个预解析线程,用来分析 HTML 文件中包含的 JavaScript、CSS 等相关文件,解析到相关文件之后,预解析线程会提前下载这些文件。
  • CDN 来加速 JavaScript 文件的加载,压缩 JavaScript 文件的体积。
  • JavaScript 文件中没有操作 DOM 相关代码,就可以将该 JavaScript 脚本设置为异步加载,通过 async 或 defer 来标记代码。
总结:

我们知道了一个HTML页面的一个大概渲染流程, CSS 和 JavaScript 都会影响到 DOM 的生成,这样我们就可以在渲染过程中尽量避免影响渲染速度的操作,加快DOM的生成和DOM树的构建,理解了这些,能让我们很好地去优化首屏渲染的速度。


转载:https://blog.csdn.net/baidu_38242832/article/details/117003116
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场