13-2 JS如何影响DOM树的构建
什么是DOM?
渲染引擎无法直接识别网络进程传递的 HTML 字节流,而 DOM 就是能理解的结构
-
DOM的作用:
1、页面 – DOM是生成页面的 基础数据结构
2、JS脚本 – DOM提供了 JS脚本操作的接口,JS可以修改 DOM 结构、样式、内容
3、安全 – 不安全的内容 在 DOM 解析阶段就被拒了
DOM树如何生成
渲染引擎内有一个HTML解析器(HTML Parser
):将HTML字节流转换为DOM结构(并不是等到整个文档加载完之后再开始解析,而是 网络进程加载了多少数据就解析多少 – 网络进程和渲染进程之间的管道)
HTML解析器做了什么
以下方字节流为例
1、通过 分词器 将字节流转换为 Token
Token
分为 Tag Token
和文本 Token
,其中Tag Token
还分为StartTag
和 EndTag
2、将 Token 解析为 DOM 节点,并将 DOM 节点添加到 DOM 树中
-
关于父子节点的判定:
HTML 解析器维护了一个
Token
栈结构,该 Token 栈主要用来计算节点之间的父子关系,第一阶段中生成的Token
依次被压入栈中(文本 Token 不需要压入到栈中) -
举例看下
JS在生成DOM树期间的影响
-总结:所以渲染引擎在 遇到 JavaScript 脚本 时,不管该脚本是否操纵了 CSSOM,都会先执行 CSS 文件下载,解析操作,再执行 JavaScript 脚本。
1/3、HTML字节流中内嵌<script>
标签
<html>
<body>
<div>1</div>
<script>
let div1 = document.getElementsByTagName('div')[0]
div1.innerText = 'time.geekbang'
</script>
<div>test</div>
</body>
</html>
-
和正常仅HTML字节流区别:
解析到
script
标签时,渲染引擎判断这是一段脚本,此时 HTML 解析器就会 暂停 DOM 的解析,因为接下来的JS可能要修改当前已经生成的 DOM 结构
2/3、在页面中引入JS文件
- 和上方解析过程的差异:
其整个执行流程还是一样的,执行到 script
标签时, 暂停 DOM 的解析,执行JS代码,不过这里执行JS 时,需要先下载这段JS代码(JS文件的下载过程会阻塞 DOM 解析)
由于js文件的下载受到网络环境、js文件大小等多种因素的影响,所以Chrome也做了很多优化,其中最主要的就是 预解析操作【预解析操作:当 渲染进程收到字节流之后,会开启一个预解析线程,用来分析 HTML 文件中包含的 JavaScript、CSS 等相关文件,解析到相关文件之后,预解析线程会 提前下载 这些文件】
3/3、在js文件中出现CSS相关操作
<html>
<head>
<style src='theme.css'></style>
</head>
<body>
<div>1</div>
<script>
let div1 = document.getElementsByTagName('div')[0]
div1.innerText = 'time.geekbang' // 需要 DOM
div1.style.color = 'red' // 需要 CSSOM
</script>
<div>test</div>
</body>
</html>
JS 代码出现了 div1.style.color = 'red'
的语句,它是用来操纵 CSSOM
的,所以在执行 JavaScript
之前,需要先解析 JavaScript 语句之上所有的 CSS 样式。所以如果代码里引用了外部的 CSS 文件,那么在执行 JavaScript 之前,还需要 等待外部的 CSS 文件下载完成,并解析生成 CSSOM 对象之后,才能执行 JavaScript 脚本。