02- 浏览器运行原理

发布于:2025-05-20 ⋅ 阅读:(23) ⋅ 点赞:(0)


注:整个JS高级专栏依托于coderwhy老师的课程,相关图片、代码均来自于其课程。

1. 网页的解析过程

输入地址 —> DNS解析 —> 服务器响应 —> 浏览器响应
一个网页URL从输入到浏览器中,到显示经历怎样的过程呢?
在这里插入图片描述

浏览器内核

常见的浏览器内核:
在这里插入图片描述
我们常说的浏览器内核指的是浏览器的排版引擎,也称之为页面渲染引擎样板引擎

2. 浏览器渲染流程

详细内容可看我的另一篇博客:
浏览器渲染原理
在这里插入图片描述

2.1 解析html

因为默认情况下服务器会给浏览器返回index…html文件,所以解析HTML是所有步骤的开始:
解析HTML,会构建DOM Tree:
在这里插入图片描述

2.2 生成css规则

浏览器在解析html时遇到 css 的<link>时会开启另外一个线程对css文件进行下载,这也就不会影响到dom tree的生成;
下载完css文件后就会对其进行解析,生成对应的cssom树。
在这里插入图片描述

2.3 构建render tree

当有了DOM TreeCSSOM Tree两部分之后,就可以结合来生成Render Tree了。
在这里插入图片描述

注意❗️

  1. link元素不会阻塞DOM Tree的构建,但是会阻塞Render Tree的构建,因为构建Render Tree需要对应的CSSOM Tree
  2. DOM TreeRender Tree并不是一一对应的,有些dom可能设置了display: none;,不会在Render Tree中出现。

2.4 布局(Layout)

布局是确定呈现树中所有节点的宽度、高度和位置信息

Render Tree形成之后,就可以对dom的style进行计算:

  1. emrem%等转换成px

2.5 绘制(Paint)

  • 在绘制阶段,浏览器将布局阶段计算的每个frame转为屏幕上实际的像素点;
  • 包括将元素的可见部分进行绘制,比如文本、颜色、边框、阴影、替换元素(比如img)
    在这里插入图片描述

3. 回流和重绘

3.1 回流reflow

(1)理解:

  • 第一次确定节点的位置和大小叫做布局(Layout);
  • 之后对于节点大小以及位置等的计算叫做回流。

(2)出现情况

  1. DOM结构发生改变(添加新节点或者移除节点);
  2. 布局改变(修改了width、height、padding等值);
  3. 窗口resize(修改了窗口的尺寸);
  4. 调用getComputedStyle方法获取尺寸、位置信息;

3.2 重绘repaint

(1)理解:

  • 第一次渲染内容叫做绘制(Paint);
  • 之后重新渲染叫做重绘(repaint)。

(2)出现情况

  1. 修改背景色、边框颜色、文字颜色、模糊样式等
  2. 回流一定引起重绘,所以回流是很消耗性能的事情。

所以在开发中要尽量避免回流

  1. 修改样式时尽量一次性修改
    • 比如通过cssText修改,通过添加class修改。
  2. 尽量避免频繁的操作DOM
    • 我们可以在一个DocumentFragment(了解即可)或者是父元素中将要操作的DOM操作完成,在一次性的操作。
  3. 尽量避免通过getComputedStyle获取尺寸、位置等信息
  4. 对某些元素使用positionabsolutefixed
    • 这种操作并不是不会引起回流,而是相对来说开销较小,不会对其他元素造成影响。

3. 特殊解析composite合成 和性能优化

绘制的过程,浏览器会将布局后的元素绘制到多个合成图层中(这是浏览器的一种优化手段);

  • 默认情况下,标准流的元素会被绘制到同一个图层中;
  • 而某些特殊的属性,会单独创建一个新的合成层,并且新的图层可以使用GPU加速绘制(每个合成层都是单独进行渲染)

哪些属性可以形成新的合成层呢?下面是常见的一下属性:

  • 3D transforms
  • videocanvasiframe
  • opacity动画转换
  • position: fixed
  • will-cahnge:一个实验性的属性,提前告诉浏览器可能会发生哪些变化
  • animationtransition设置了opacitytransform

注❗️:
分层确实可以提高性能,但是它以内存管理为代价,因此不应作为web性能优化策略的一部分过度使用!

4. defer和async属性

首先来了解一下 script和页面解析的关系 !

前面我们已经知道了,浏览器在解析html时遇到<link>不会影响DOM Tree的构建,那遇到<script>呢?会影响吗?
答案是:会的!

  • 浏览器在遇到<script>时会先停止对DOM Tree构建,转而去下载、执行js脚本;
  • 只有js脚本执行完毕后,DOM Tree才能继续进行构建;

那这是为什么呢?

  • 因为js文件中可能存在对DOM的操作;
  • 若先构建DOM Tree,再执行js脚本,可能会造成严重的回流和重绘,影响页面性能。

但是这也会带来新的问题,特别是现在主流框架:

  • 目前主要流行的VueReact,脚本往往比html页面更"重",处理时间更长,
  • 也就是在js脚本执行结束前,页面可能出现空白

(有些浏览器可能对此做了优化,也就是在js脚本执行接受之前,先将已经构建的DOM Tree进行展示)
在这里插入图片描述

为了解决这个问题,<script>给我们提供了两个属性:deferasync

4.1 defer

  • defer会告诉浏览器不要等待脚本的下载,继续执行DOM Tree的构建
  • 脚本的下载有浏览器完成,不会影响DOM Tree的构建;
  • 若脚本先下载完,那它会等待DOM Tree构建完成,在DOMContentLoaded事件执行前执行defer中的代码

在这里插入图片描述
总结:

  1. defer不会影响DOM Tree的构建;
  2. deferDOM Tree已经构建完成,可进行对dom的操作;
  3. defer总是在DOMContentLoaded时间发出前执行;
  4. 另外,有多个defer会按照编写顺序执行;
  5. 从某种角度来说,defer会提高页面性能,并且推荐放在<head>中(提前下载js脚本);
  6. 注意:defer仅适用于外部脚本,对于<script>默认内容会被忽略。

4.2 async

  • asyncdefer相似,都能够让脚本不堵塞页面;
  • async是完全独立于浏览器的:
    • 浏览器页面不会因为script脚本而暂停DOM Tree的构建;
    • async脚本不能保证顺序执行脚本,它独立下载,独立运行,不会等待其他脚本;
    • async不一定在DOMContentLoaded时间执行前执行

总结:

  1. defer通常需要在文档解析后操作DOMjavascript代码,并且对多个script文件有顺序要求;
  2. async通常用于独立的脚本,对其他脚本,甚至DOM没有依赖的:

网站公告

今日签到

点亮在社区的每一天
去签到