浏览器渲染基本原理

目录

1.浏览器中有哪些主要进程

浏览器进程

网络进程

渲染进程

2.事件循环

3.异步

3.浏览器渲染基本流程

解析HTML

样式计算

布局-layout

分层

绘制

分块

光栅化

画出屏幕最终成像

reflow

repaint


1.浏览器中有哪些主要进程

浏览器进程

主要负责界面显示,用户交互,子进程管理等。浏览器进程内部会启动多个线程处理不同的任务。

网络进程

负责加载网络资源。网络进程会启动多个线程来处理不同的网络任务。

渲染进程

渲染进程启动后,会开启一个渲染主线程,主要负责执行HTML,CSS,JS代码,渲染页面。

默认情况下,浏览器会为每个标签页开启一个新的渲染进程,以保证不同的标签页之间互不影响。

2.事件循环

事件循环又称消息循环,是浏览器渲染主线程的工作方式。

通常,他会开启一个无限循环,每次从消息队列中取出一个任务执行,而其他线程只需要在合适的时候将任务加入到消息队列末尾即可。

过去把消息队列简单的分为微队列和宏队列,这种说法目前已经无法满足复杂的浏览器环境,取而代之的是一种更加灵活多变的处理方式。

根据W3C官方解释,每个任务有不同的类型,同类型的任务必须在同一个队列,不同的任务可以在不同队列。不同的任务队列有不同的优先级,在一次事件循环中有浏览器自行决定任务队列的调度优先级。但浏览器必须有一个微任务队列,且其一定具有最高优先级,必须优先调度执行。

3.异步

JS是一门单线程语言,其运行在浏览器渲染进程的主线程上,一个渲染进程只有一个主线程,而主线程却又承担着渲染页面,执行JS,CSS,HTML等诸多工作。如果使用同步的方式,有可能会造成阻塞,浪费主线程的宝贵时间;还可能导致页面无法及时更新,给用户造成“卡死”现象。

所以采用异步的方式来避免。具体的做法:当某些任务发生时,比如计时器,网络,事件监听等。渲染主线程会将任务交给其他线程取处理,自生立即结束任务的执行,转而执行后续代码。当其他线程完成处理后,会将事先传递的回调函数包装成任务,加到消息队列末尾排队,等待渲染主线程调度执行。

在这种异步模式下,浏览器永不阻塞,从而最限度的保证了单线程的流畅运行。

3.浏览器渲染基本流程

当用户在地址栏输入URL后,浏览器会向服务器发送请求,待网络进程获取到返回的HTML文档后,会生成一个渲染任务,并将其放入消息队列,浏览器主线程则会通过事件循环从消息队列中取出任务,开启渲染流程。

渲染流程主要分为解析HTML,样式计算,布局,分层,绘制,分块,光栅化,画八个步骤,每一个步骤都有严格的输入和输出,上一个步骤的输出会成为下一个步骤的输入。

解析HTML

解析其实就是将收到的字符串形式的HTML文档转化成一个树结构的对象,方便后续步骤的操作,同时给JS开放一些DOM编程接口。

为了提高解析效率,在解析之前,浏览器会开启一个预解析线程,用来下载外部的CSS和JS文件。

在解析过程中,渲染主线程遇到JS执行JS,遇到CSS执行CSS

如果解析到link位置,而外部CSS文件还没下载好,主线程不会等待,而是继续执行后续代码。这是因为CSS的文件下载解析是在预解析线程内进行的,这也是CSS不会阻塞HTML的根本原因。

如果解析到script位置,而外部JS文件还没下载好,主线程会等待JS文件下载完成,并执行完全局代码后,再继续执行后续代码。因为JS的执行可能会修改当前DOM树,这也就是JS会阻塞HTML的根本原因。

第一步完成后会得到一颗DOM树和一颗CSSOM树,浏览器的默认样式,内部样式,外部样式,行内样式均会在CSSOM树中

样式计算

渲染主线程会遍历得到的DOM树,为每一个节点计算出它的最终样式。

在这一步中,许多预设值会变成绝对值,比如red,white会变成对应的RGB值;许多相对单位会变成绝对单位,比如%,rem,vw会变成px。

第二部完成后会得到一颗带有样式的DOM树

布局-layout

主线程会遍历DOM树的每一个节点,计算出它的几何的信息。如:节点的宽高,相对包含块位置

值得注意的是:布局树和DOM总不是一一对应的,比如:

{display:none}的节点,再DOM树中存在,但在布局树中没有几何信息;

伪选择器::after等在布局树中有几何信息,在DOM树种却不存在;

又比如匿名行盒,匿名块盒等

第三步,布局的结果就是布局树

分层

浏览器会采用一套复杂的策略对布局树进行分层。

分层的好处是将来某一层的信息发生了改变,只需要对该层进行后续处理,从而提升效率。

第四步分层的结果就是得到一个个的层信息

绘制

渲染主线程会为每一层单独产生一套绘制指令,用于描述这一层该如何画出来。

第五步绘制的结果就是得到绘制信息

分块

绘制完成后,浏览器会将绘制信息提交给合成线程,后续工作交由合成线程来完成。

合成线程会对每个图层进行分块,划分成更小的块区域。

第六步分块的结果就是得到块信息

光栅化

完成分块后,合成线程会将块信息提交给GPU进程,以极高的速度完成光栅化,并且会优先处理靠近视窗的块。

第七步光栅化的结果就是得到,一块块块的位图

画出屏幕最终成像

合成线程拿到每个层,每个块的位图后,会生成一个个的 [ 指引 (quad) ] 信息。

指引信息会标识出每一个位图应该画到屏幕上哪个位置,以及会考略旋转,缩放等变形。

最后,合成线程会把生成的指引信息提交给GPU进程,GPU进程产生系统调用,将信息提交给GPU硬件,由GPU硬件画出屏幕最终成像。

值得的是:由于变形是发生在合成线程的,与渲染主线程无关,也就不会产生repaint和reflow。这也及时transform效率高的本质原因

reflow

reflow 的本质就是重新计算 layout 树。

当进行了会影响布局树的操作后,需要重新计算布局树,会引发 layout。

为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 reflow 是异步完成的。

也同样因为如此,当 JS 获取布局属性时,就可能造成无法获取到最新的布局信息。

repaint

repaint 的本质就是重新根据分层信息计算了绘制指令。

当改动了可见样式后,就需要重新计算,会引发 repaint。

由于元素的布局信息也属于可见样式,所以 reflow 一定会引起 repaint。

---------------------------------------------------------------------------------------------------------------------------------

该内容为学习笔记,如有不准确之处,还望不吝指正。

  • 20
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值