“从浏览器输入url到页面显示经历了哪些?”
一个很是
常见的问题,看了该系列绝对能惊到面试官,可能就由于这一道面试题就收了你呢!嘿嘿。做者简介:koala,专一完整的 Node.js 技术栈分享,从 JavaScript 到 Node.js,再到后端数据库,祝您成为优秀的高级 Node.js 工程师。【程序员成长指北】做者,Github 博客开源项目 github.com/koala-codin…javascript
DOM是Document Object Model(文档对象模型)的缩写css
W3C 文档对象模型 (DOM) 是中立于平台和语言的接口,它容许程序和脚本动态地访问和更新文档的内容、结构和样式。-这是W3Cschool给的概念html
看了上面的概念好像太“官方”,解释就是 DOM 是对 HTML 文档结构化的表述,后端服务器返回给浏览器渲染引擎的 HTML 文件字节流是没法直接被浏览器渲染引擎理解的,要转化为渲染器引擎能够理解的内部结构,这个结构就是 DOM。 W3C 那个概念我好像尚未把它所有翻译完,“容许程序和脚本动态地访问和更新文档的内容、结构和样式”。这里其实就是DOM的做用了前端
本文我主要以 Webkit 渲染引擎来说解,Safari 和 Chrome 都使用 Webkit。Webkit 是一款开源渲染引擎,它原本是为 linux 平台研发的,后来由 Apple 移植到 Mac 及 Windows 上。java
先看一张总体的流程图linux
从后端返回给浏览器渲染引擎 HTML 文件字节流, 第一步要通过的就是渲染引擎中的 HTML 解析器。它实现了将 HTML 字节流转换为 DOM树 结构。 HTML 文件字节流返回的过程当中 HTML 解析器就一直在解析,边加载边解析哦(这里注意下,有些文章写的有问题)。git
例子1:最简单的不带 CSS 和 JavaScript 的 HTML 代码讲解 HTML 解析器程序员
<html>
<body>
<div>程序员成长指北</div>
</body>
</html>
复制代码
根据这段代码具体分析 HTML 解析器作了哪些事github
读取 HTML 的原始字节流,并根据文件的指定编码(例如 UTF-8)将它们转换成各个字符。 并将字符串转换成 W3C HTML5 标准规定的各类令牌,例如,“”、“”,以及其余尖括号内的字符串。每一个令牌都具备特殊含义和一组规则。面试
一堆字节流 bytes
3C 62 6F ...
复制代码
转成正常的html文件
<html>
<body>
<div>
koala
<p>
程序员成长指北
</P>
</div>
</body>
</html>
复制代码
分词器将字节流转换为一个一个的 Token,Token 分为 Tag Token和文本 Token,上面这段代码最后分词器转化后的结果是:
HTML 解析器维护了一个 Token 栈结构(数据结构真是个好东西),这个栈结构的目的就是用来计算节点间的父子关系,在上一个阶段生成的 Token 会被顺序压到这个栈中,如下是具体规则:
父节点
就是栈中相邻的那个元素生成的 DOM节点父节点
就是当前栈顶 Token 所对应的 DOM 节点。此时应该搞懂了核心图中 HTML 解析器的部分,和 DOM 树的基本绘制流程,可是现实很残酷,哪里有这么简单的前端代码,还有有 JavaScript 和 CSS 呢!继续往下看
CSS 解析器最终的目的也是构建树不过它构建的树是 CSSOM 树 树的构建流程和 DOM 树的构建流程基本相同
body { font-size: 16px }
div { font-weight: bold }
div p { display: none }
复制代码
看下最后构造的 CSSOM 树
CSSOM 为什么具备树结构?为页面上的任何对象计算最后一组样式时,浏览器都会先从适用于该节点的最通用规则开始(例如,若是该节点是 body 元素的子项,则应用全部 body 样式),而后经过应用更具体的规则(即规则“向下级联”)以递归方式优化计算的样式。
以上面的 CSSOM 树为例进行更具体的阐述。span 标记内包含的任何置于 body 元素内的文本都将具备 16 像素字号,而且颜色为红色 — font-size 指令从 body 向下级联至 span。不过,若是某个 span 标记是某个段落 (p) 标记的子项,则其内容将不会显示。
注意点:
- CSS解析能够与DOM解析同进行
- 若是只有 CSS 和 HTML 的页面,CSS 不会影响 DOM 树的建立,可是若是页面中还有 JavaScript,结论就不同了,请继续往下看。
上面两个例子中都尚未javascript的出现,接下来讲下JavaScript 对 DOM 树和 CSSOM 树构建的影响。
状况1:当前页面中只有 Html 和 JavaScript,并且 JavaScript 非外部引入
DOM 树构建时当遇到JavaScript脚本,就要暂停 DOM 解析,先去执行Javascript,由于在JavaScript可能会操做当前已经生成的DOM节点。
有一点须要注意:javascript是可能操做当前已经生成的DOM节点,若是是后面还未生成的DOM节点是不生效的,好比这段代码:
<html>
<body>
<div>1</div>
<script> let div1 = document.getElementsByTagName('div')[0] div1.innerText = '程序员成长指北' let div2 = document.getElementsByTagName('div')[1] div2.innerText = 'kaola' </script>
<div>test</div>
</body>
</html>
复制代码
显示结果为两行: 第一行结果是程序员成长指北 第二行记过是test 由于在执行第三行和第四行 script 脚本的时候,DOM树中尚未生成第二个 div对应的dom节点。
状况2:当页面中同时有Html JavaScript CSS ,并且都非外部引入
DOM 树构建时当遇到 JavaScript 脚本,就要暂停 DOM 解析,先去执行 JavaScript,同时 JavaScript 还要判断 CSSOM 是否解析完成,由于在 JavaScript 可能会操做 CSSOM 节点,CSSOM 节点确认解析完成,执行 JavaScript 再次回到 DOM 树建立。(因此这里也能够所CSS解析间接影响DOM树建立)
状况3:当页面中同时有Html,JavaScript, CSS ,并且外部引入
Webkit渲染引擎有一个优化,当渲染进程接收HTML文件字节流时,会先开启一个预解析线程,若是遇到 JavaScript 文件或者 CSS 文件,那么预解析线程会提早下载这些数据。当渲染进程接收 HTML 文件字节流时,会先开启一个预解析线程,若是遇到 JavaScript 文件或者 CSS 文件,那么预解析线程会提早下载这些数据。DOM树在建立过程当中若是遇到JavaScript文件,接下来就和状况2类型同样了。
影响关系图: 画了一张影响关系图但愿你们更好的记忆:
经过 DOM 树和 CSSOM 树,浏览器就能够经过两者构建渲染树了。浏览器会先从 DOM 树的根节点开始遍历每一个可见节点,而后对每一个可见节点找到适配的CSS样式规则并应用。具体的规则有如下几点须要注意:
Render Tree和DOM Tree不彻底对应。
请注意 visibility: hidden 与 display: none 是不同的。前者隐藏元素,但元素仍占据着布局空间(即将其渲染成一个空框),然后者 (display: none) 将元素从渲染树中彻底移除,元素既不可见,也不是布局的组成部分
看一下前问中提到的 DOM 树和 CSSOM 树最终合成的渲染树结果是:
看完了渲染树的造成,在开发过程当中咱们能作哪些优化?(注意这里的优化只是针对渲染树造成部分,其余的优化会在系列文章以后继续讲)
看完这篇文章赶忙检测一下你写的前端代码,脑补一下渲染树造成过程,想一想本身代码有没有须要改善的地方,系列文章会继续分享,下篇该系列文章渲染树的布局与绘制以及虚拟DOM树出现的必要性,感谢观看。
极客时间浏览器专栏
浏览器渲染原理: srtian96.gitee.io/blog/2018/0…
以为不错点个Star,欢迎 加群 互相学习。