浏览器原理3

Posted by Panda on 2020-03-02

浏览器原理3

DOM 树

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

  • 从⻚⾯的视⻆来看,DOM 是⽣成⻚⾯的基础数据结构。
  • 从 JavaScript 脚本视⻆来看,DOM 提供给 JavaScript 脚本操作的接⼝,通过这套接⼝,
    JavaScript 可以对 DOM 结构进⾏访问,从⽽改变⽂档的结构、样式和内容。
  • 从安全视⻆来看,DOM 是⼀道安全防护线,⼀些不安全的内容在 DOM 解析阶段就被拒之⻔外了。

DOM 树

  • HTML 解析器(HTMLParser)
  • ⽹络进程加载了多少数据,HTML 解析器便解析多少数据。
  • ⽹络进程接收到响应头之后,会根据响应头中的 content-type 字段来判断⽂件的类型,⽐如 contenttype
    的值是“text/html”,那么浏览器就会判断这是⼀个 HTML 类型的⽂件,然后为该请求选择或
    者创建⼀个渲染进程。渲染进程准备好之后,⽹络进程和渲染进程之间会建⽴⼀个共享数据的管道,
    ⽹络进程接收到数据后就往这个管道⾥⾯放,⽽渲染进程则从管道的另外⼀端不断地读取数据,并同
    时将读取的数据“喂”给 HTML 解析器。你可以把这个管道想象成⼀个“⽔管”,⽹络进程接收到的
    字节流像⽔⼀样倒进这个“⽔管”,⽽“⽔管”的另外⼀端是渲染进程的 HTML 解析器,它会动态接
    收字节流,并将其解析为 DOM。

image

  1. 通过分词器将字节流转换为 Token。
  2. 第⼆个和第三个阶段是同步进⾏的,需要将 Token 解析为 DOM 节点,并将 DOM 节点添加到 DOM
    树中。

HTML 解析器维护了⼀个 Token 栈结构,该 Token 栈主要⽤来计算节点之间的⽗⼦关系,在第⼀个阶
段中⽣成的 Token 会被按照顺序压到这个栈中。

  • 如果压⼊到栈中的是 StartTag Token,HTML 解析器会为该 Token 创建⼀个 DOM 节点,然后将该
    节点加⼊到 DOM 树中,它的⽗节点就是栈中相邻的那个元素⽣成的节点。

  • 如果分词器解析出来是⽂本 Token,那么会⽣成⼀个⽂本节点,然后将该节点加⼊到 DOM 树中,
    ⽂本 Token 是不需要压⼊到栈中,它的⽗节点就是当前栈顶 Token 所对应的 DOM 节点。

  • 如果分词器解析出来的是 EndTag 标签,⽐如是 EndTag div,HTML 解析器会查看 Token 栈顶的
    元素是否是 StarTag div,如果是,就将 StartTag div 从栈中弹出,表⽰该 div 元素解析完成。

1
2
3
4
5
6
<html>
<body>
<div>1</div>
<div>test</div>
</body>
</html>

HTML 解析器开始⼯作时,会默认创建了⼀个根为 document 的空 DOM 结构

image
image
image
image
image

在实际⽣产环境中,HTML 源⽂件中既包含 CSS 和 JavaScript,⼜包含图⽚、⾳频、视频等⽂件,所
以处理过程远⽐上⾯这个⽰范 Demo 复杂。

JavaScript 是如何影响 DOM ⽣成的

  • 当解析到 内嵌 JavaScript 脚本标签时,HTML 解析器暂停⼯作,JavaScript 引擎介⼊,并执⾏
    script 标签中的脚本, 脚本会修改 DOM 中内容,脚本执⾏完成之后,HTML 解析器恢复解析过
    程,继续解析后续的内容,直⾄⽣成最终的 DOM

  • JavaScript ⽂件的下载过程会阻塞 DOM 解析。

  • Chrome 浏览器做了很多优化,其中⼀个主要的优化是预解析操作。当渲染引擎收到字节流之后,
    会开启⼀个预解析线程,⽤来分析 HTML ⽂件中包含的 JavaScript、CSS 等相关⽂件,解析到相
    关⽂件之后,预解析线程会提前下载这些⽂件。

  • 使⽤ CDN 来加速 JavaScript ⽂件的加载,压缩 JavaScript ⽂件的体积。

  • 可以将该 JavaScript 脚本设置为异步加载,通过 async 或 defer 来标记代码

在执⾏ JavaScript 之前,需要先解析 JavaScript 语句之上所有的 CSS 样式。所以如果代码⾥引⽤了
外部的 CSS ⽂件,那么在执⾏ JavaScript 之前,还需要等待外部的 CSS ⽂件下载完成,并解析⽣成
CSSOM 对象之后,才能执⾏ JavaScript 脚本。

不管该脚本是否操纵了 CSSOM,都会执⾏ CSS ⽂件下载,解析操作,再执⾏ JavaScript 脚本。
总结:JavaScript 会阻塞 DOM ⽣成,⽽样式⽂件⼜会阻塞 JavaScript 的执⾏