本日,我们来理解一下 HTML 和网页有什么关系,以及与 DOM 有什么不同。
通过本讲内容,你将节制浏览器是怎么处理 HTML 内容的,以及在这个过程中我们可以进行若何的处理来提升网页的性能,从而提升用户的体验。

一、浏览器页面加载过程

不知你是否有过这样的体验:当打开某个浏览器的时候,创造一贯在转圈,或者等了好永劫光才打开页面……

此时的你,会选择关掉页面还是耐心等待呢?

html页面数据结构HTML页面根本构造和加载进程 Python
(图片来自网络侵删)

这一征象,除了网络不稳定、网速过慢等缘故原由,大多数都是由于页面设计不合理导致加载韶光过长导致的。

我们都知道,页面是用 HTML/CSS/JavaScript 来编写的。

HTML 的职责在于奉告浏览器如何组织页面,以及搭建页面的基本构造;CSS 用来装饰 HTML,让我们的页面更好看;JavaScript 则可以丰富页面功能,使静态页面动起来。

HTML由一系列的元素组成,常日称为HTML元素。
HTML 元素常日被用来定义一个网页构造,基本上所有网页都是这样的 HTML 构造:

<html> <head></head> <body></body></html>

个中:

html元素是页面的根元素,它描述完全的网页;head元素包含了我们想包含在 HTML 页面中,但不肯望显示在网页里的内容;body元素包含了我们访问页面时所有显示在页面上的内容,是用户终极能看到的内容;

HTML 中的元素特殊多,个中还包括可用于 Web Components 的自定义元素。

前面我们提到页面 HTML 构造不合理可能会导致页面相应慢,这个过程很多时候表示在<script>和<style>元素的设计上,它们会影响页面加载过程中对 Javascript 和 CSS 代码的处理。

因此,如果想要提升页面的加载速率,就须要理解浏览器页面的加载过程是若何的,从根本上来办理问题。

浏览器在加载页面的时候会用到 GUI 渲染线程和 JavaScript 引擎线程(更详细的浏览器加载和渲染机制将在第 7 讲中先容)。
个中,GUI 渲染线程卖力渲染浏览器界面 HTML 元素,JavaScript 引擎线程紧张卖力处理 JavaScript 脚本程序。

由于 JavaScript 在实行过程中还可能会改动界面构造和样式,因此它们之间被设计为互斥的关系。
也便是说,当 JavaScript 引擎实行时,GUI 线程会被挂起。

以网易云教室官网为例,我们来看看网页加载流程。

(1)当我们打开官网的时候,浏览器会从做事器中获取到 HTML 内容。

(2)浏览器获取到 HTML 内容后,就开始从上到下解析 HTML 的元素。

(3)<head>元素内容会先被解析,此时浏览器还没开始渲染页面。

我们看到<head>元素里有用于描述页面元数据的<meta>元素,还有一些<link>元素涉及外部资源(如图片、CSS 样式等),此时浏览器会去获取这些外部资源。
除此之外,我们还能看到<head>元素中还包含着不少的<script>元素,这些<script>元素通过src属性指向外部资源。

(4)当浏览器解析到这里时(步骤 3),会停息解析并下载 JavaScript 脚本。

(5)当 JavaScript 脚本下载完成后,浏览器的掌握权转交给 JavaScript 引擎。
当脚本实行完成后,掌握权会交回给渲染引擎,渲染引擎连续往下解析 HTML 页面。

(6)此时<body>元素内容开始被解析,浏览器开始渲染页面。

在这个过程中,我们看到<head>中放置的<script>元素会壅塞页面的渲染过程:把 JavaScript 放在<head>里,意味着必须把所有 JavaScript 代码都下载、解析和解释完成后,才能开始渲染页面。

到这里,我们就明白了:如果外部脚本加载韶光很长(比如一贯无法完成下载),就会造成网页永劫光失落去相应,浏览器就会呈现“假去世”状态,用户体验会变得很糟糕。

因此,对付对性能哀求较高、须要快速将内容呈现给用户的网页,常常会将 JavaScript 脚本放在<body>的末了面。
这样可以避免资源壅塞,页面得以迅速展示。
我们还可以利用defer/async/preload等属性来标记<script>标签,来掌握 JavaScript 的加载顺序。

百度首页

三、DOM 解析

对付百度这样的搜索引擎来说,必须要在最短的韶光内供应到可用的做事给用户,个中就包括搜索框的显示及可交互,除此之外的内容优先级会相对较低。

浏览器在渲染页面的过程须要解析 HTML、CSS 以得到 DOM 树和 CSS 规则树,它们结合后才天生终极的渲染树并渲染。
因此,我们还常常将 CSS 放在<head>里,可用来避免浏览器渲染的重复打算。

二、HTML 与 DOM 有什么不同

我们知道<p>是 HTML 元素,但又常常将<p>这样一个元素称为 DOM 节点,那么 HTML 和 DOM 到底有什么不一样呢?

根据 MDN 官方描述:文档工具模型(DOM)是 HTML 和 XML 文档的编程接口。

也便是说,DOM 是用来操作和描述 HTML 文档的接口。
如果说浏览器用 HTML 来描述网页的构造并渲染,那么利用 DOM 则可以获取网页的构造并进行操作。
一样平常来说,我们利用 JavaScript 来操作 DOM 接口,从而实现页面的动态变革,以及用户的交互操作。

在开拓过程中,常常用工具的办法来描述某一类事物,用特定的构造凑集来描述某些事物的凑集。
DOM 也一样,它将 HTML 文档解析成一个由 DOM 节点以及包含属性和方法的干系工具组成的构造凑集。

三、DOM 解析

我们常见的 HTML 元素,在浏览器中会被解析成节点。
比如下面这样的 HTML 内容:

<html> <head> <title>标题</title> </head> <body> <a href='xx.com'>我的超链接</a> <h1>页面第一标题</h1> </body></html>

打开掌握台 Elements 面板,可以看到这样的 HTML 构造,如下图所示:

在浏览器中,上面的 HTML 会被解析成这样的 DOM 树,如下图所示:

我们都知道,对付树状构造来说,常常利用parent/child/sibling等办法来描述各个节点之间的关系,对付 DOM 树也不例外。

举个例子,我们常常会对页面功能进行抽象,并封装成组件。
但不管怎么进行整理,页面终极依然是基于 DOM 的树状构造,因此组件也是呈树状构造,组件间的关系也同样可以利用parent/child/sibling这样的办法来描述。
同时,现在大多数运用程序同样以root为根节点展开,我们进行状态管理、数据管理也常常会呈现出树状构造。

四、事宜委托

我们知道,浏览器中各个元素从页面中吸收事宜的顺序包括事宜捕获阶段、目标阶段、事宜冒泡阶段。
个中,基于事宜冒泡机制,我们可以实现将子元素的事宜委托给父级元向来进行处理,这便是事宜委托。

如果我们在每个元素上都进行监听的话,则须要绑定三个事宜;(假设页面上有a,b,c三个兄弟节点)

function clickEventFunction(e) { console.log(e.target === this); // logs `true` // 这里可以用 this 获取当前元素}// 元素a,b,c绑定element2.addEventListener("click", clickEventFunction, false);element5.addEventListener("click", clickEventFunction, false);element8.addEventListener("click", clickEventFunction, false);

利用事宜委托,可以通过将事宜添加到它们的父节点,而将事宜委托给父节点来触发处理函数:

function clickEventFunction(event) { console.log(e.target === this); // logs `false` // 获取被点击的元素 const eventTarget = event.target; // 检讨源元素`event.target`是否符合预期 // 此处掌握广告面板的展示内容}// 元素1绑定element1.addEventListener("click", clickEventFunction, false);

这样能办理什么问题呢?

绑定子元素会绑定很多次的事宜,而绑定父元素只须要一次绑定。
将事宜委托给父节点,这样我们对子元素的增加和删除、移动等,都不须要重新进行事宜绑定。

常见的利用办法紧张是上述这种列表构造,每个选项都可以进行编辑、删除、添加标签等功能,而把事宜委托给父元素,不管我们新增、删除、更新选项,都不须要手动去绑定和移除事宜。

如果在列表数量内容较大的时候,对成千上万节点进行事宜监听,也是不小的性能花费。
利用事宜委托的办法,我们可以大量减少浏览器对元素的监听,也是在前端性能优化中比较大略和根本的一个做法。

把稳:

如果我们直接在document.body上进行事宜委托,可能会带来额外的问题;由于浏览器在进行页面渲染的时候会有合成的步骤,合成的过程会先将页面分身分歧的合成层,而用户与浏览器进行交互的时候须要吸收事宜。
此时,浏览器会将页面上具有事宜处理程序的区域进行标记,被标记的区域会与主线程进行通信。
如果我们document.body上被绑定了事宜,这时候全体页面都会被标记;纵然我们的页面不关心某些部分的用户交互,合成器线程也必须与主线程进行通信,并在每次事宜发生时进行等待。
这种情形,我们可以利用passive: true选项来办理

五、总结

我们理解了 HTML 的浸染,以及它是如何影响浏览器中页面的加载过程的,同时还先容了利用 DOM 接口来掌握 HTML 的展示和功能逻辑。
我们理解了DOM解析事宜委托等干系观点。

true选项来办理

五、总结

我们理解了 HTML 的浸染,以及它是如何影响浏览器中页面的加载过程的,同时还先容了利用 DOM 接口来掌握 HTML 的展示和功能逻辑。
我们理解了DOM解析事宜委托等干系观点。