浏览器是如何将标签转成 DOM ?

时间: 2019-12-03阅读: 93标签: 标签

浏览器基本的工作流程

进入主话题之前,先罗列一下浏览器的主要构成:

  1. 用户界面- 包括地址栏、后退/前进按钮、书签目录等,也就是你所看到的除了用来显示你所请求页面的主窗口之外的其他部分
  2. 浏览器引擎- 用来查询及操作渲染引擎的接口
  3. 渲染引擎- 用来显示请求的内容,例如,如果请求内容为html,它负责解析html及css,并将解析后的结果显示出来
  4. 网络- 用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作
  5. UI 后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口
  6. JS解释器- 用来解释执行JS代码
  7. 数据存储- 属于持久层,浏览器需要在硬盘中保存类似cookie的各种数据,HTML5定义了web database技术,这是一种轻量级完整的客户端存储技术



解析

当浏览器获得了资源以后要进行的第一步工作就是 HTML 解析,,它由几个步骤组成:编码、预解析、标记和构建树。


编码

HTTP 响应主体的有效负载可以是从HTML文本到图像数据的任何内容。解析器的第一项工作是找出如何转制刚刚从服务器接收到的 bit。

假设我们正在处理一个HTML文档,解码器必须弄清楚文本文档是如何被转换成比特(bit)的,以便反转这个过程。


记住,最终即使是文本也会被计算机翻译成二进制,如上图所示,在本例中是 ASCII 编码—定义二进制值,如“01000100”表示字母“D”。

对于文本存在许多可能的编码—浏览器的工作是找出如何正确地解码文本。服务器应该通过 Content-Type 提供的信息同时在文本文件头部使用 Byte Order Mark 告知浏览器编码格式。

如果仍然无法确定编码,浏览器还会自行匹配一种解码格式来处理数据。有时候,解码格式也会写在 <meta> 标签中。

最坏的情况是,浏览器进行了有根据的猜测,然后开始解析之后发现一个矛盾的 <meta> 标签。在这些罕见的情况下,解析器必须重新启动,丢弃之前解码的内容。浏览器有时必须处理旧的 web内容(使用遗留编码),许多这样的系统都支持这一点。

我们现在经常在 HTML中使用的文件格式是 UTF-8,那是因为 UTF-8 能较完整的支持Unicode 字符范围,同时与 CSS、JavaScript 中常见的节字符具有良好的 ASCII 兼容性。一般浏览器默认的解码格式也是 UTF-8。当解码出错的时候,我们会看到屏幕上全部都是乱码字符。


预解析

在执行脚本时,其他线程会解析文档的其余部分,找出并加载需要通过网络加载的其他资源。通过这种方式,资源可以在并行连接上加载,从而提高总体速度。请注意,预解析器不会修改 DOM 树,而是将这项工作交由主解析器处理;预解析器只会解析外部资源(例如外部脚本、样式表和图片)的引用。

预解析器不是完整的解析器,如,它不理解 HTML 中的嵌套级别或父/子关系。但是,预解析可以识别特定的 HTML 标签的名称和属性,以及 URL。例如,如果你的 HTML 内容中有一个<img src="https://somewhere.example.com/​images/​dog.png" alt=""> ,预解析将注意到src属性,并将获取这个图片的请求加到请求队列中。

请求图片的速度越快越好,将等待它从网络到达的时间降到最低。预解析还会注意到 HTML 中的某些显式请求,比如 preload 和 prefetch 指令,并将它们加入等待队友中进行处理。


标记化(Tokenization)

该算法的输出结果是 HTML 标记。该算法使用状态机来表示。每一个状态接收来自输入信息流的一个或多个字符,并根据这些字符更新下一个状态。当前的标记化状态和树结构状态会影响进入下一状态的决定。这意味着,即使接收的字符相同,对于下一个正确的状态也会产生不同的结果,具体取决于当前的状态。该算法相当复杂,无法在此详述,所以我们通过一个简单的示例来帮助大家理解其原理。

基本示例 - 将下面的 HTML 代码标记化:

<html>
  <body>
    Hello world
  </body>
</html>

初始状态是数据状态。遇到字符 < 时,状态更改为“标记打开状态”。接收一个 a-z 字符会创建“起始标记”,状态更改为“标记名称状态”。这个状态会一直保持到接收 > 字符。在此期间接收的每个字符都会附加到新的标记名称上。在本例中,我们创建的标记是 html 标记。

遇到 > 标记时,会发送当前的标记,状态改回“数据状态”。<body> 标记也会进行同样的处理。目前 html 和 body 标记均已发出。现在我们回到“数据状态”。接收到 Hello world 中的 H 字符时,将创建并发送字符标记,直到接收 </body> 中的 <。我们将为 Hello world 中的每个字符都发送一个字符标记。

现在我们回到“标记打开状态”。接收下一个输入字符 / 时,会创建 end tag token 并改为“标记名称状态”。我们会再次保持这个状态,直到接收 >。然后将发送新的标记,并回到“数据状态”。</html> 输入也会进行同样的处理。



构建树(tree construction)

在创建解析器的同时,也会创建 Document 对象。在树构建阶段,以 Document 为根节点的 DOM 树也会不断进行修改,向其中添加各种元素。标记生成器发送的每个节点都会由树构建器进行处理。规范中定义了每个标记所对应的 DOM 元素,这些元素会在接收到相应的标记时创建。这些元素不仅会添加到 DOM 树中,还会添加到开放元素的堆栈中。此堆栈用于纠正嵌套错误和处理未关闭的标记。其算法也可以用状态机来描述。这些状态称为“插入模式”。

在上一步符号化以后,解析器获得这些标记,然后以合适的方法创建 DOM 对象并将这些符号插入到 DOM 对象中。DOM 对象的数据结构是树状的,所以这个过程称为构造树(tree construction)。另外,在 IE 的历史中,大部分时间里没有使用树结构。


在创建解析器的同时,也会创建 Document 对象。在树构建阶段,以 Document 为根节点的 DOM 树也会不断进行修改,向其中添加各种元素。标记生成器发送的每个节点都会由树构建器进行处理。

规范中定义了每个标记所对应的 DOM 元素,这些元素会在接收到相应的标记时创建。这些元素不仅会添加到 DOM 树中,还会添加到开放元素的堆栈中。此堆栈用于纠正嵌套错误和处理未关闭的标记。其算法也可以用状态机来描述。这些状态称为“插入模式”。

例如,考虑这个 HTML:

<p>sincerely<p>The authors</p>

这样可以确保结果树中的两个段落对象是兄弟节点,而忽略第二个打开的标签则与一个段落对象相对。 HTML表可能是解析器规则试图确保表具有适当结构的最复杂的表。

尽管存在所有复杂的解析规则,但是一旦创建了 DOM 树,所有试图创建正确 HTML 结构的解析规则就不再强制执行了。

使用 JavaScript,网页可以几乎以任何方式重新排列 DOM 树,即使它没有意义,例如,添加表格单元格作为 <video> 标签的子项,渲染系统负责弄清楚如何处理任何前后不一致标签。

HTML 解析中的另一个复杂因素是 JavaScript 可以在解析器执行其工作时添加更多要解析的内容。<script> 标签包含解析器必须收集的文本,然后发送到脚本引擎进行评估。 当脚本引擎解析并评估脚本文本时,解析器会等待。如果JavaScript文件内调用了 document.writeAPI,解析器将重新开始解析过程。


事件(Events)

当解析器完成时,它通过一个名为 DOMContentLoaded 的事件宣布完成。事件是内置在浏览器中的广播系统,JavaScript可以侦听和响应它。除了 DOMContentLoaded 事件,还有load 事件(表示所有资源已经加载完成,包括图片、视频、CSS等等)、unload 事件表示界面即将关闭、鼠标事件键盘事件等等。

浏览器在 DOM 中创建一个事件对象,并将其打包成有用的状态信息(例如屏幕上触摸的位置、按下的按键等等),当JavaScript触发事件的时候,就会同时产生事件对象。

DOM 的树结构通过允许在树的任何级别监听事件(如在树根、树叶或两者之间的任何地方)。在目标元素上触发事件的时候,需要 从DOM 树的根元素开始向子元素查找,这个过程俗称事件捕捉阶段。到达目标元素以后,还要逐级向上返回到根元素上,这个过程俗称事件冒泡阶段


还可以取消一些事件,例如,如果表单没有正确填写,则可以停止表单提交。(提交事件是从<form> 元素触发的,JavaScript 侦听器可以检查表单,如果字段为空或无效,还可以选择取消事件。)


DOM

HTML语言提供了丰富的特性集,远远超出了解析器处理的标记。解析器构建一个结构,其中的元素包含其他元素,以及这些元素最初具有什么状态(它们的属性)。结构和状态的组合足以提供基本渲染和一些交互(例如通过内置控件,如<textarea>,<video>,<button>等)。 但是如果不添加 CSS 和 JavaScript,网络将非常枯燥(和静态)。 DOM 为 HTML 元素和与 HTML 无关的其他对象提供了额外的功能层。

元素接口

在解析器将元素放入DOM树之前,解析器会根据不同元素的名称赋予元素不同的接口功能。些通用特性包括:

  • 访问代表元素子元素的全部或子集的 HTML 集合
  • 能够查找元素的属性、子元素和父元素
  • 重要的是,创建新元素的方法(不使用解析器),并将它们附加到树中(或将它们从树中分离出来)

对于像 <table> 这样的特殊元素,该接口包含用于查找表中所有行,列和单元格的其他特定于表的功能,以及用于从表中删除和添加行和单元格的快捷方式。 同样,<canvas> 接口具有绘制线条,形状,文本和图像的功能。 使用这些 API 需要 JavaScript 仅仅使用 HTML 标签是不够的。

每当我们使用 JavaScript 操作 DOM 的时候,将会触发浏览器的一些连锁反应,这些反应是为了让更改后的页面更快的渲染在屏幕上。例如:

  • 用数字代表通用的元素名称和属性,浏览器用使用哈希表进行快速识别这些数字
  • 将频繁变更的子元素进行缓存,方便子元素快速迭代
  • 将 sub-tree 的跟踪变化降到最低,避免‘污染’整个 DOM 树

其他API

DOM中的HTML元素及其接口是浏览器在屏幕上显示内容的唯一机制。CSS可以影响布局,但仅限于HTML元素中存在的内容。最终,如果你想在屏幕上看到内容,它必须通过作为树的一部分的HTML接口来完成。

  1. 访问存储系统(数据库,key/value存储,网络缓存存储(network cache storage));
  2. 设备(各种类型的地理定位,距离和方向传感器,USB,MIDI,蓝牙,游戏手柄);
  3. 网络(HTTP交换,双向服务器套接字,实时媒体流);
  4. 图形(2D和3D图形基元,着色器,虚拟和增强现实);
  5. 和多线程(具有丰富消息传递功能的共享和专用执行环境)。

随着主要浏览器引擎开发和实施新的Web标准,DOM公开的功能不断增加。然而,DOM的这些“额外”API中的大多数都超出了本文的范围。


总结

希望这部分对你关于 DOM 解析过程多多少少有点帮助,共进步!

原文:https://itnext.io/how-the-browser-renders-a-web-page-dom-cssom-and-rendering-df10531c9969
作者:Uday Hiwarale
译者:前端小智  
吐血推荐

1.站长广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入...

2.休闲娱乐: 直播/交友    优惠券领取   网页游戏   H5游戏

链接: http://www.fly63.com/article/detial/7134

video标签的属性

HTML5是下一代HTML,新增了许多新的标签,这些标签实现了许多新的功能。并且还减少了对外部插件的要求同时也可以更好的处理错误。比如HTML5中的video标签就可以很好的实现了在页面上播放视频的效果。

小程序如何写动态标签

动态配置标签的好处一是所有逻辑在JS端控制,二是使得我们的模板非常规范,方便后续维护更新,碎片模板可以很好的控制,三是我们可以根据使用场景很方便的配置props的属性

自动播放页面中所有audio标签

在浏览游戏百科中的BGM部分,想把页面中的音频像音乐播放器一样自动地一首接一首播放,参考了这篇博客以后,写了以下代码,在开发者工具的控制台里运行就行。应该说适用范围比上述参考博客要广,不受DOM树结构影响

META标签的设置

<meta> 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词。<meta> 标签位于文档的头部,不包含任何内容。<meta> 标签的属性定义了与文档相关联的名称/值对。

meta标签中的http-equiv属性使用

http-equiv顾名思义,相当于http的文件头作用,它可以向浏览器传回一些有用的信息,以帮助正确和精确地显示网页内容,与之对应的属性值为content,content中的内容其实就是各个参数的变量值。 meta标签的http-equiv属性语法格式是:

a标签调用js的几种方法

<a> 标签的 href 属性用于指定超链接目标的 URL,href 属性的值可以是任何有效文档的相对或绝对 URL,包括片段标识符和 JavaScript 代码段。其中javascript:是伪协议,它可以让我们通过一个链接来调用javascript函数.而采用这个方式 javascript:;

HTML5表单标签

Form表单主要用于用户与Web应用程序进行数据的交互,它允许用户将数据发给web应用程序,网页也可以拦截数据的发送以便自己使用。form通常由一到多个表单元素组成,这些表单元素是单行/多行文本框,下拉菜单,按钮,复选框,单选按钮

总结那些有默认margin,padding值的html标签

h1~h6标签:有默认margin(top,bottom且相同)值,没有默认padding值。dl标签:有默认margin(top,bottom且相同)值,没有默认padding值。ol,ul标签:有默认margin-(top,bottom且相同)值,有默认padding-left值

XPath当匹配标签判断text()判断内容失败的问题及解决

在爬取网站的时候我使用XPath去抓取网页上的内容,XPath表达式来精准获取需要的标签内容。当我对如下一段html代码编写XPath表达式抓取的时候出现了问题,代码如下。片名两个字中间有七个空格,我想要获取<dd></dd>中的内容。

HTML标签嵌套规则

块级元素总是在新行上开始,高度、行高以及上下边距都可控制,宽度默认是容器的100%,除非设定宽度。行内元素和其他元素都在一行上,高、行高、以及上下边距不可变,宽度就是它的文字和图片的宽度,不可改变。

fly63.com版权所有,内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权,请与小编联系!情况属实本人将予以删除!

文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全