[TOC]
JavaScript是如何影响DOM树构建的
渲染流水线中,后面的步骤都是直接或者间接地依赖于DOM结构。
网络数据流路径来介绍DOM树是怎么生成的。
基于DOM树的解析流程,介绍:
- 在解析过程中遇到js脚本,dom解析器是如何处理的
- dom解析器是如何处理跨站点资源的
什么是DOM
从网络传给渲染引擎的HTML文件字节流是无法直接被渲染引擎理解的,所以要将其转化为渲染引擎能够理解的内部结构,这个就是DOM。
DOM提供了对HTML文档结构化的表述。在渲染引擎中,DOM有三个层面的作用。
- 从页面的视角来看,DOM是生成页面的基本数据结构。
- 从js脚本视角来看,DOM提供给js脚本操作的接口,通过这套接口,js可以对dom结构进行访问,从而改变文档的结构 样式 内容。
- 从安全视角来看,DOM是一道安全防护线,一些不安全的内容在DOM解析阶段就被拒之门外了。
简言之,DOM 是表述 HTML 的内部数据结构,它会将 Web 页面和 JavaScript 脚本连接起来,并过滤一些不安全的内容。
DOM树如何生成
1
test
<script>标签之前,所有的解析流程还是和之前介绍的一样<br />但是解析到<script>标签时,渲染引擎判断这是一段脚本,此时 HTML 解析器就会暂停 DOM 的解析,因为接下来的 JavaScript 可能要修改当前已经生成的 DOM 结构。
//foo.js let div1 = document.getElementsByTagName(‘div’)[0] div1.innerText = ‘time.geekbang’
1
test
内嵌js脚本修改成通过 js文件加载。其整个执行流程还是一样的,执行到js标签时,暂停整个dom解析,执行js代码,<br />不过这执行js时,需要先下载这段js代码,这里需要重点关注下载环境,因为js下载过程会阻塞dom解析,而通常下载又是非常耗时的,会受到网络环境 js大小等因素的影响。<br />CHrome浏览器做了很多优化, 其中一个主要的优化是**预解析操作**。当渲染引擎收到字节流之后,会开启一个预解析线程,用来分析 HTML 文件中包含的 JavaScript、CSS 等相关文件,解析到相关文件之后,预解析线程会提前下载这些文件。<br />**cdn 压缩 async defer**<br />async 和 defer 虽然都是异步的,不过还有一些差异,**使用 async 标志的脚本文件一旦加载完成,会立即执行**;**而使用了 defer 标记的脚本文件,需要在 DOMContentLoaded 事件之前执行。**
//theme.css div {color:blue}
1
test
该示例中,JavaScript 代码出现了 div1.style.color = ‘red' 的语句,它是用来操纵 CSSOM 的,所以在执行 JavaScript 之前,需要先解析 JavaScript 语句之上所有的 CSS 样式。所以如果代码里引用了外部的 CSS 文件,那么在执行 JavaScript 之前,还需要等待外部的 CSS 文件下载完成,并解析生成 CSSOM 对象之后,才能执行 JavaScript 脚本。<br />而 JavaScript 引擎在解析 JavaScript 之前,是不知道 JavaScript 是否操纵了 CSSOM 的,**所以渲染引擎在遇到 JavaScript 脚本时,不管该脚本是否操纵了 CSSOM,都会执行 CSS 文件下载,解析操作,再执行 JavaScript 脚本。**
我们知道了** JavaScript 会阻塞 DOM 生成,而样式文件又会阻塞 JavaScript 的执行**,所以在实际的工程中需要重点关注 JavaScript 文件和样式表文件,使用不当会影响到页面性能的。<br />**XSSAuditor**<br />是用来检测词法安全的。在分词器解析出来 Token 之后,它会检测这些模块是否安全,比如是否引用了外部脚本,是否符合 CSP 规范,是否存在跨站点请求等。如果出现不符合规范的内容,XSSAuditor 会对该脚本或者下载任务进行拦截。
1