HTML页面基本结构和加载过程

529 阅读4分钟

浏览器页面的加载过程

  1. 浏览器在加载页面的时候会用到GUI渲染引擎和JavaScript引擎线程,其中GUI渲染引擎负责渲染浏览器界面HTML元素;JavaScript引擎线程负责处理JavaScript脚本程序

  2. 网页加载流程如下:

    1.1当我们打开网页的时候,浏览器会从服务器中获取HTML内容

    1.2浏览器获取到HTML内容后,开始从上到下解析HTML元素

    1.3head元素内容会先被解析,此时浏览器还没有开始渲染页面(head元素中有包含描述页面元数据的meta元素,还有一些link元素涉及到外部资源,如图片和CSS样式,此时浏览器会向服务器并行请求CSS样式、图片或视频。继续渲染后面的代码;当服务器返回图片文件或者视频文件的时候,浏览器会重新渲染这部分代码。head元素中还包含不少的script元素,通过src属性指向外部资源)

    1.4当浏览器解析到步骤3(script的src属性指向外部资源),会暂停解析并下载JavaScript脚本

    1.5当JavaScript脚本下载完成后,浏览器的控制权交给JavaScript引擎。当脚本执行完成后,控制权会交回给渲染引擎,渲染引擎继续往下解析HTML页面

    1.6此时,body元素内容开始被解析,浏览器开始渲染页面

因此,如果外部脚本加载时间很长,就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,用户体验很差。为了提高网页性能,我们通常将JavaScript脚本放在body的最后面;将样式表放在head最前面

我们也可以通过defer/async/preload等属性来标记script标签,来控制JavaScript的加载顺序。

  1. script标签的 defer/async/preload 属性 <script src='xxx.js' defer></script>
    设置defer属性会并行下载JavaScript脚本,等页面全部加载完成以后才会按顺序执行

执行过程为:浏览器解析HTML页面,解析过程中发现带有defer属性的script标签,浏览器继续往下解析HTML页面同时并行下载script标签中的外部脚本。浏览器完成解析HTML页面后再执行下载的脚本

<script src='xxx.js' async></script>

设置async属性将不会依赖于任何js和css的执行。js脚本下载完成之后会立刻执行,不能保证按照书写的顺序执行,哪个脚本先下载完成就先执行哪个脚本

执行过程为:浏览器解析HTML页面,解析过程中发现带有async属性的script标签,浏览器继续往下解析HTML页面同时并行下载script标签中的外部脚本。脚本下载完成后,浏览器暂停解析HTML页面开始执行下载的脚本,脚本执行完毕后浏览器恢复解析HTML页面

一般来说,如果脚本之间没有依赖关系就用async属性;如果脚本之间有依赖关系就用defer属性。如果同时使用async和defer属性,defer属性失效。

HTML和DOM

浏览器用HTML来描述网页的结构并渲染;DOM用来获取网页的结构并进行操作

随着应用程序越来越复杂,DOM操作越来越频繁,频繁的DOM操作会导致页面频繁的进行计算和渲染,导致不小的性能开销。于是虚拟DOM被提出

虚拟DOM是用来模板真实DOM的中间产物,它的设计大致分为以下3个过程:

1.用JavaScript对象模拟DOM树,得到一颗虚拟DOM树

2,当页面数据变更时,生成新的虚拟DOM树,比较新旧两颗虚拟DOM树的差异

3.把差异应用到真正的DOM树上

事件委托

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

使用事件委托的方式,我们可以大量减少浏览器对元素的监听,也是前端性能优化中比较简单和基础的一个做法

需要注意的是,如果我们直接在document.body上进行事件委托,可能会带来额外的问题