进入主话题之前,先罗列一下浏览器的主要构成:
当浏览器获得了资源以后要进行的第一步工作就是 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 指令,并将它们加入等待队友中进行处理。
该算法的输出结果是 HTML 标记。该算法使用状态机来表示。每一个状态接收来自输入信息流的一个或多个字符,并根据这些字符更新下一个状态。当前的标记化状态和树结构状态会影响进入下一状态的决定。这意味着,即使接收的字符相同,对于下一个正确的状态也会产生不同的结果,具体取决于当前的状态。该算法相当复杂,无法在此详述,所以我们通过一个简单的示例来帮助大家理解其原理。
基本示例 - 将下面的 HTML 代码标记化:
<html>
<body>
Hello world
</body>
</html>
初始状态是数据状态。遇到字符 < 时,状态更改为“标记打开状态”。接收一个 a-z 字符会创建“起始标记”,状态更改为“标记名称状态”。这个状态会一直保持到接收 > 字符。在此期间接收的每个字符都会附加到新的标记名称上。在本例中,我们创建的标记是 html 标记。
遇到 > 标记时,会发送当前的标记,状态改回“数据状态”。<body> 标记也会进行同样的处理。目前 html 和 body 标记均已发出。现在我们回到“数据状态”。接收到 Hello world 中的 H 字符时,将创建并发送字符标记,直到接收 </body>中的 <。我们将为 Hello world 中的每个字符都发送一个字符标记。
现在我们回到“标记打开状态”。接收下一个输入字符 / 时,会创建 end tag token 并改为“标记名称状态”。我们会再次保持这个状态,直到接收 >。然后将发送新的标记,并回到“数据状态”。</html> 输入也会进行同样的处理。
在创建解析器的同时,也会创建 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,解析器将重新开始解析过程。
当解析器完成时,它通过一个名为 DOMContentLoaded 的事件宣布完成。事件是内置在浏览器中的广播系统,JavaScript可以侦听和响应它。除了 DOMContentLoaded 事件,还有load 事件(表示所有资源已经加载完成,包括图片、视频、CSS等等)、unload 事件表示界面即将关闭、鼠标事件键盘事件等等。
浏览器在 DOM 中创建一个事件对象,并将其打包成有用的状态信息(例如屏幕上触摸的位置、按下的按键等等),当JavaScript触发事件的时候,就会同时产生事件对象。
DOM 的树结构通过允许在树的任何级别监听事件(如在树根、树叶或两者之间的任何地方)。在目标元素上触发事件的时候,需要 从DOM 树的根元素开始向子元素查找,这个过程俗称事件捕捉阶段。到达目标元素以后,还要逐级向上返回到根元素上,这个过程俗称事件冒泡阶段。
还可以取消一些事件,例如,如果表单没有正确填写,则可以停止表单提交。(提交事件是从<form> 元素触发的,JavaScript 侦听器可以检查表单,如果字段为空或无效,还可以选择取消事件。)
HTML语言提供了丰富的特性集,远远超出了解析器处理的标记。解析器构建一个结构,其中的元素包含其他元素,以及这些元素最初具有什么状态(它们的属性)。结构和状态的组合足以提供基本渲染和一些交互(例如通过内置控件,如<textarea>,<video>,<button>等)。 但是如果不添加 CSS 和 JavaScript,网络将非常枯燥(和静态)。 DOM 为 HTML 元素和与 HTML 无关的其他对象提供了额外的功能层。
在解析器将元素放入DOM树之前,解析器会根据不同元素的名称赋予元素不同的接口功能。些通用特性包括:
对于像 <table> 这样的特殊元素,该接口包含用于查找表中所有行,列和单元格的其他特定于表的功能,以及用于从表中删除和添加行和单元格的快捷方式。 同样,<canvas> 接口具有绘制线条,形状,文本和图像的功能。 使用这些 API 需要 JavaScript 仅仅使用 HTML 标签是不够的。
每当我们使用 JavaScript 操作 DOM 的时候,将会触发浏览器的一些连锁反应,这些反应是为了让更改后的页面更快的渲染在屏幕上。例如:
DOM中的HTML元素及其接口是浏览器在屏幕上显示内容的唯一机制。CSS可以影响布局,但仅限于HTML元素中存在的内容。最终,如果你想在屏幕上看到内容,它必须通过作为树的一部分的HTML接口来完成。
随着主要浏览器引擎开发和实施新的Web标准,DOM公开的功能不断增加。然而,DOM的这些“额外”API中的大多数都超出了本文的范围。
您的浏览器禁用了JS脚本运行,请启用该功能。怎么解除浏览器禁用js?这篇文章将总结整理各个浏览器如何开启、禁用javascript的方法总汇。
浏览器使用流式布局模型 (Flow Based Layout)。浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了Render Tree。有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。
IE6不支持min-height,解决办法使用css hack,ol内li的序号全为1,不递增。解决方法:为li设置样式display: list-item;定位父元素overflow: auto;,包含position: relative;子元素,子元素高于父元素时会溢出。解决办法:
由于不同的浏览器默认的样式也不同,所以在网页开发前设置一个公用样式,来清除各个浏览器的默认样式,已达到做的网页在各个浏览器中达到统一。
浏览器访问网站的步骤:Chrome搜索自身的DNS缓存、读取本地HOST文件、浏览器发起一个DNS的一个系统调用、浏览器获得域名对应的IP地址后,发起HTTP三次握手、TCP/IP连接建立起来、服务器端接受到了这个请求、浏览器根据拿到的资源对页面进行渲染
Browsh是一个纯文本浏览器,可以运行在大多数的TTY终端环境和任何浏览器。目前,终端客户端比浏览器客户端更先进。终端客户端即时更新和交付,以便于体验新的功能,例如,你可以观看视频。
一般说的浏览器内核是指浏览器最重要的核心部分,RenderingEngine,翻译成中文大概意思就是“解释引擎”,我们一般称为浏览器内核。由于不同的内核各自有一套自己的渲染网页和解释页面代码的机制,所以就会有一些问题存在。
主流浏览器之争从上个世纪开就开始,已经持续了很长的时间。人们都在笑话IE,纷纷转向其它浏览器。今天,我向大家分享一下针对IE的搞笑图片,只是逗乐而已,喝杯咖啡,坐下来慢慢享受吧。
有时候我们希望在浏览器中执行一些低优先级的任务,比如记录统计数据、做一些耗时的数据处理等,暂且将其称为后台任务。这些任务跟动画计算、合成帧、响应用户输入等高优先级的任务共享主线程
浏览器的事件循环,前端再熟悉不过了,每天都会接触的东西。但我以前一直都是死记硬背:事件任务队列分为macrotask和microtask,浏览器先从macrotask取出一个任务执行,再执行microtask内的所有任务,接着又去macrotask取出一个任务执行
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!