HTML
一、浏览器页面加载过程
1、问题一:
页面 HTML 结构不合理可能会导致页面响应慢,这个过程很多时候体现在<script
和<style>
元素的设计上,它们会影响页面加载过程中对 Javascript 和 CSS 代码的处理。
2、浏览器页面加载过程:
- GUI 渲染线程负责渲染浏览器界面 HTML 元素
- JavaScript 引擎线程 主要负责处理 JavaScript 脚本程序
- 互斥关系,当其中一个执行另外一个会被挂起
3、网页加载流程:
- 首先,GUI 渲染线程开启工作。
<head>
元素内容开始被解析,此时浏览器还没有开始渲染页面。- 当浏览器解析到
<head>
元素中的<script>
元素,这些<script>
元素通过src
属性指向外部资源。 - 此时浏览器会暂停解析并下载 JavaScript 脚本,当 JavaScript 脚本下载完后,GUI 渲染线程挂起,JavaScript引擎开始工作。当脚本执行完成后,GUI 渲染线程继续往下解析 HTML 页面。
- 此时
<body>
元素开始被解析,浏览器开始渲染页面。
<head>
中放置的<script>
元素加载的外部脚本时间太长(比如一直无法完成下载),就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,用户体验会非常糟糕。
4、解决办法:
- 将 JavaScript 脚本放在
<body>
的最后面,避免资源阻塞,页面可以迅速展示。 - 使用
defer/async/preload
等属性来标记<script>
标签,来控制 JavaScript 的加载顺序。(推荐async
)
5、知识点补充:
浏览器渲染页面过程需要解析 HTML、CSS 以得到 DOM 树和 CSS 规则树,它们结合后才会生成最终的渲染树进行渲染。因此,我们把 CSS 放在<head>
中,可用来避免浏览器渲染的重新计算。
二、HTML 与 DOM 有什么不同
浏览器用 HTML 来描述网页的结构并渲染,那么使用 DOM 则可以获取网页的结构并进行操作。
1、DOM 解析(DOM 是个树状结构)
- 我们常常会对页面功能进行抽象,并封装成组件。但不管怎么进行整理,页面最终依然是基于 DOM 的树状结构,因此组件也是呈树状结构的。
- 现在大多数应用程序同样以
root
为跟节点展开,我们进行状态管理、数据管理也常常会呈现出树状结构。
2、操作 DOM
频繁的 DOM 操作会导致页面频繁地进行计算和渲染,导致不小的性能开销,所以出现了虚拟 DOM ,在 Vue 和 React 框架中都有体现。
虚拟 DOM 的设计大致可以分为 3 个过程:
- 用 JavaScript 对象模拟 DOM 数,得到一颗虚拟 DOM 树。
- 当页面数据变更时,生成新的虚拟 DOM 树,比较新旧两颗虚拟 DOM 树的差异。
- 把差异应用到真正的 DOM 树上。
3、事件委托
浏览器中各个元素从页面中接收事件的顺序包括事件捕获阶段、目标阶段、事件冒泡阶段。其中,基于事件冒泡机制,我们可以实现将子元素的事件委托给父级元素来进行处理,这便是事件委托。
- 绑定子元素会绑定很多次的事件,而绑定父元素只需要一次绑定。
- 将事件委托给父节点,这样我们对子元素的增加和删除、移动等,都不需要重新进行事件绑定。
4、使用事件委托的方式,我们可以大量减少浏览器对元素的监听,也是在前端性能优化中比较简单和基础的一个做法。
三、小结
-
我们要对一些基础内容进行不定期地复习,这些原本认为已经固话的认知,在重新学习的过程中,或许可以得到新的理解。
-
比如,虚拟 DOM 的设计参考了网页中 DOM 设计的很多地方(树状结构,DOM 属性),却又通过简化、新旧对比的方式巧妙地避开了容易出现性能瓶颈的地方,从而提升了页面渲染的性能。
-
再比如,很多前端框架在检测数据变更的时候采用了树状结构,也是因为即使我们对应用进行了模块化、组件化,最终它在浏览器页面中的呈现和组织方式也依然是树状的,而树状的方式也很好地避免了循环依赖的问题。