前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • HTTP

    • 基础篇

      • HTTP的前世今生
      • HTTP是什么
      • HTTP世界全览
      • HTTP分层
      • 键入网址到回车发生什么
      • HTTP报文是什么样子的
      • 理解请求方法
      • URI
      • 响应状态码
      • HTTP有哪些特点
      • HTTP优缺点
      • HTTP的实体数据
      • HTTP传输大文件
      • HTTP的连接管理
      • HTTP的重定向
      • HTTP的Cookie机制
      • HTTP的缓存控制
      • HTTP的代理服务
      • HTTP的缓存代理
    • 高级篇

    • 扩展篇

  • 浏览器相关

  • 计算机基础

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

DOM树:JavaScript是如何影响DOM树构建的|浏览器篇

# DOM树:JavaScript是如何影响DOM树构建的

30 秒速记

  • DOM 是渲染流水线的关键中间结构,后续多个阶段都会直接或间接依赖它。
  • 分析页面构建时,应沿网络字节流进入渲染引擎的路径,关注数据如何逐步形成 DOM 树。
  • 解析器遇到 JavaScript 后需要协调脚本执行与文档解析,因为脚本可能改变已经生成的节点。
  • 跨站资源会让解析过程涉及额外的资源获取与处理,不能只看本地 HTML 的结构转换。

DOM 是渲染流程的基础结构,而 JavaScript 会通过暂停解析或修改节点,直接影响它的构建。 浏览器会把网络字节流逐步转成字符和令牌,再边下载边生成树,并按 HTML 规则补全或修正部分结构。遇到普通脚本时,解析器要先等脚本执行完,因为脚本可能通过 document.write 或节点操作改变当前文档。跨站资源不会改变树构建算法,但网络延迟、同源策略、CORS 和内容安全策略可能影响资源能否及时使用。

在上一篇文章中,我们通过开发者工具中的网络面板,介绍了网络请求过程的几种性能指标以及对页面加载的影响。

而在渲染流水线中,后面的步骤都直接或者间接地依赖于 DOM 结构,所以本文我们就继续沿着网络数据流路径来介绍 DOM 树是怎么生成的。然后再基于 DOM 树的解析流程介绍两块内容:第一个是在解析过程中遇到 JavaScript 脚本,DOM 解析器是如何处理的?第二个是 DOM 解析器是如何处理跨站点资源的?

原理拆解: 网络层交付的是字节流,渲染引擎先依据编码把它转换为字符,再由 HTML 解析器进行词法处理、生成令牌,并按照树构建规则创建和挂接节点。这个过程通常是流式的,不必等完整文档下载完才开始,所以下载与解析能够交叠进行。生成的 DOM 不只是元素标签的镜像:浏览器还会补全某些隐含结构,并按照 HTML 解析规则纠正部分不规范嵌套。

具体例子: 解析器遇到没有 async、defer 的外部经典脚本时,会暂停后续文档解析,等待脚本取得并立即执行,因为脚本可能通过 document.write、节点插入或删除改变当前文档。脚本执行时只能可靠访问已经解析完成的前置节点;位于其后的元素尚未进入 DOM。带 defer 的经典脚本可在文档解析完成后、DOMContentLoaded 前按文档顺序执行,从而减少对树构建的阻塞。

边界与排查: 跨站脚本、图片或接口并不会因为来源不同就改变 DOM 的基本树构建算法,但会受到网络延迟、同源策略、CORS、内容安全策略等约束。图片下载通常不阻塞 DOM 构建,而同步脚本可能阻塞;不能把所有外部资源统一归类为“阻塞解析”。动态插入的脚本及模块脚本也有不同的调度语义,应按具体类型判断。

工程验证: 可在脚本前后分别调用 document.getElementById,观察后置节点在同步脚本执行时是否为 null;再将脚本改为 defer 对比结果。开发者工具的网络瀑布图能确认脚本等待时间,性能面板中的解析事件、脚本任务和 DOMContentLoaded 时间则可用于确认阻塞发生在哪一段。

面试官追问

追问 1接口监控显示首页 HTML 在几十毫秒内返回,前端负责人因此断言首屏迟迟不出现一定与文档解析无关,你会如何反驳?
参考回答

这个结论不成立,网络层交付的只是字节流,浏览器仍要完成字符转换、分词和树构建才能得到 DOM。同步脚本还可能暂停解析,因此响应快速不等于结构及时可用;最终首屏时间也会受后续渲染环节影响。

追问 2一个服务端输出的长页面包含多个同步外部脚本,你会怎样调整脚本加载,既减少树构建阻塞又保证依赖完整文档的代码能运行?
参考回答

可优先评估将经典脚本标记为 defer,使其下载时不阻塞文档解析,并在解析完成后、DOMContentLoaded 前执行。依赖关系与执行顺序需要按脚本类型验证;若代码依赖解析过程中的即时写入,直接改造可能改变行为。

追问 3同一段脚本从文档末尾移到首个内容节点之前后,调用 document.getElementById 得到 null,代码本身没有变化,原因是什么?
参考回答

同步脚本执行时只能可靠访问已经完成解析的前置节点,位于脚本后的元素尚未加入 DOM。移动位置改变了脚本执行时可见的树,而不是选择器语义;可改用合适的加载时序,但要留意由此带来的执行顺序变化。

追问 4线上性能面板显示 DOMContentLoaded 明显推迟,同时网络瀑布图里一个经典脚本等待很久,你会怎样确认它是否阻塞了 DOM 构建?
参考回答

应对齐网络瀑布中的脚本等待区间、性能面板中的解析事件和脚本任务,检查解析是否在脚本取得与执行期间暂停。还可在脚本前后探测后置节点是否存在,并改为 defer 做对照;图片等外部资源通常不阻塞 DOM,不能把所有请求一起归因。

追问 5安全评审把跨站图片、跨站脚本和跨站接口统一标成“都会改变 DOM 构建算法并阻塞解析”,你会怎样纠正?
参考回答

资源来源不同不会改变 DOM 的基本树构建算法,但会引入网络延迟、同源策略、CORS 或内容安全策略等约束。同步经典脚本可能阻塞解析,图片通常不会;动态脚本和模块脚本还具有不同调度语义,必须按资源类型判断。

# 什么是 DOM

30 秒速记

  • DOM 是浏览器把 HTML 字节内容转换后得到的内部结构化表示,也是生成页面的基础数据。
  • 对脚本而言,DOM 提供访问和修改文档的接口,使 JavaScript 能改变结构、样式与内容。
  • 对渲染引擎而言,原始网络字节流不能直接使用,必须先转成可理解、可处理的 DOM 结构。
  • 在安全层面,解析阶段会过滤或拒绝部分不安全内容,因此 DOM 也承担一道输入防护职责。
  • DOM 同时连接文档、脚本与渲染流程,频繁或错误的修改会直接改变页面最终状态。

DOM 是浏览器对 HTML 文档的内部结构化表示,也是页面、脚本和渲染流程之间的连接层。 网络传来的字节流不能直接用于渲染,必须先转换成浏览器能够理解和处理的树形结构。对 JavaScript 来说,它提供了一套访问和修改文档的接口,因此脚本可以改变页面结构、样式和内容。解析阶段还会拒绝部分不安全内容,所以 DOM 在生成页面之外,也承担了一层输入防护作用。

从网络传给渲染引擎的 HTML 文件字节流是无法直接被渲染引擎理解的,所以要将其转化为渲染引擎能够理解的内部结构,这个结构就是 DOM。DOM 提供了对 HTML 文档结构化的表述。在渲染引擎中,DOM 有三个层面的作用

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

简言之,DOM 是表述 HTML 的内部数据结构,它会将 Web 页面和 JavaScript 脚本连接起来,并过滤一些不安全的内容。

面试官追问

追问 1后端同学把接口返回的 200 KB HTML 字符串直接称为“已经生成的 DOM”,并据此判断浏览器无需再处理,你会怎么纠正?
参考回答

这段内容仍是网络传来的字节或文本,并不是渲染引擎可直接使用的 DOM。浏览器需要解析它并建立内部节点结构,页面生成和脚本操作才有基础;解析成本与最终渲染成本也不能混为一谈。

追问 2一个富文本编辑页通过脚本修改节点内容和样式,产品要求同时把服务器上的原始模板永久改掉,你会如何界定前端改动的作用范围?
参考回答

脚本通过 DOM 接口修改的是当前文档中的结构、样式或内容,不会自动反向写回服务器模板。若要持久化,必须另行采集变更并提交给后端;保存格式、权限和冲突处理不属于 DOM 自身提供的能力。

追问 3同一份页面既要供渲染引擎生成画面,又要让埋点脚本读取节点层级,是否需要维护两套独立结构?
参考回答

通常不需要,DOM 本身就是页面生成的基础数据结构,同时向 JavaScript 提供访问和修改文档的接口。两类消费者共享这份结构,但脚本修改会改变当前文档状态;由此引起的后续渲染影响需要结合具体改动判断。

追问 4安全事故中服务端返回的页面片段含有危险内容,团队认为只要网络请求成功,所有内容就必然进入页面内部结构,你会先检查什么?
参考回答

应检查内容在解析并形成 DOM 时是否被拒绝,以及实际生成的节点结构,而不能只看响应正文。来源指出 DOM 解析承担一定安全过滤作用;具体拦截范围取决于浏览器实现,仍需配合其他安全策略,不能把它当作完整防线。

追问 5代码评审中有人建议绕过 DOM,让渲染引擎直接读取服务器返回的 HTML 字节流,以减少一层转换,你会接受吗?
参考回答

不会,网络字节流无法直接作为渲染引擎理解的页面结构,必须转化为内部的 DOM 表述。DOM 还连接页面与 JavaScript,并承担部分内容过滤职责;绕过它会同时失去结构化处理、脚本接口与这道安全边界。

# DOM 树如何生成

30 秒速记

  • HTMLParser 不会等待整个文档下载完毕,而是持续消费网络进程送来的字节流,边接收边构建 DOM。
  • 浏览器根据响应头的 content-type 判断资源类型;对 text/html,网络进程与渲染进程通过数据管道持续传递内容。
  • 解析首先把字节流切分为开始标签、结束标签和文本等 Token,随后同步完成节点创建与入树。
  • 解析器用栈维护尚未闭合的元素:开始标签创建节点并入栈,文本生成文本节点但不入栈,匹配的结束标签使对应开始标签出栈。
  • 解析开始时已有 document 根节点;新节点依据当前栈中的层级关系确定父节点,直到全部字节流处理完成。
  • 真实页面还会混入脚本、样式和媒体资源,因此基础栈模型解释结构生成,但不能覆盖所有阻塞与资源调度细节。

DOM 树由 HTMLParser 边接收网络字节流边解析生成,不需要等整个文档下载完成。 浏览器先根据 content-type 识别 text/html,再把数据持续交给渲染进程,将内容拆成开始标签、结束标签和文本等 Token。解析器通过栈维护节点层级:开始标签创建节点并入栈,文本生成文本节点,结束标签让匹配元素出栈。这个模型能说明基本结构生成,但真实页面还包含脚本、样式和媒体资源,是否阻塞要按资源类型判断。

← 页面性能分析:利用chrome做web性能分析渲染流水线:CSS如何影响首次加载时的白屏时间 →

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • HTTP

    • 基础篇

      • HTTP的前世今生
      • HTTP是什么
      • HTTP世界全览
      • HTTP分层
      • 键入网址到回车发生什么
      • HTTP报文是什么样子的
      • 理解请求方法
      • URI
      • 响应状态码
      • HTTP有哪些特点
      • HTTP优缺点
      • HTTP的实体数据
      • HTTP传输大文件
      • HTTP的连接管理
      • HTTP的重定向
      • HTTP的Cookie机制
      • HTTP的缓存控制
      • HTTP的代理服务
      • HTTP的缓存代理
    • 高级篇

    • 扩展篇

  • 浏览器相关

  • 计算机基础