浏览器、前端原理

浏览器原理1:绘制原理

2022-01-03  本文已影响0人  刘佳阔

[toc]

一、浏览器的常用进程

1.进程和线程的区别

线程可以共享地址空间和数据.而进程独享地址空间和数据.

线程比进程更轻量.所以他的切换和创建销毁更快速.

多个线程可以共享公共内存.因此更容易进行通信

线程必须在进程中运行,但是进程和线程是不同的东西,线程拥有自己的程序计数器,寄存器,和一个堆栈.

进程是资源的聚合体.而线程则是CPU上被调度的实体.线程可以访问进程地址空间中的每一个内存地址,甚至可以访问其他线程的堆栈,因此线程之间是没有保护的.

进程中的任意一线程执行出错,都会导致整个进程的崩溃。

线程之间共享进程中的数据。

当一个进程关闭之后,操作系统会回收进程所占用的内存。

进程之间的内容相互隔离。

img img

2.多进程浏览器

以chrome举例

img

二、浏览器发起http请求流程

1.构建请求

如GET /index.html HTTP1.1,构建好后,浏览器准备发起网络请求

2.查找缓存

先查找浏览器中是否有缓存,有的话拦截请求,返回缓存。如果没有,就进入网络请求

3.准备ip地址和端口

通过DNS服务获取网站对应的IP地址,同时host也有缓存:根域名服务器->顶级域名服务器->网络服务提供商缓存->路由器缓存->系统缓存->浏览器缓存

端口号没有指定的话,默认是80

4.等待TCP队列

Chrome有个机制,同一个域名同时最多只能建立6个TCP连接,如果在同一个域名下同时有10个请求发生,那么其中4个请求会进入排队等待状态,直至进行中的请求完成。如果当前请求数量少于6,会直接进入下一步,建立TCP连接

5.建立TCP链接

包括三次握手,如果使用HTTPS,还需要TLS层的四次加密协商。七次握手

6.发送HTTP请求

首先浏览器会向服务器发送请求行,它包括了请求方法、请求URI(Uniform Resource Identifier)和HTTP版本协议。然后再发送请求头(包含浏览器的一些基础信息)和请求体(GET请求不需要)

img

7.处理http响应

这里 包括处理响应和状态码,断开链接,重定向(如果状态码是301)三个步骤

img

如果响应状态码是301,则会发送重定向,需要再次请求,并读取响应头中的重定向地址作为第二次发请求的地址。

浏览器的缓存过程

DNS缓存和页面资源缓存会被缓存在浏览器中,而页面资源则是由几个请求头中的字段决定

包括Cache-Control:Max-age = 2000 表示缓存过期时间2000秒

If-None-Match:"4f80f-13c-3a1xb12a" 增加文件的etag,供后天判断资源是否是最新

http缓存

img

请求流程总结

img

三、从输入URL到页面展示的过程

img

主要职责划分

1. 用户输入

地址栏判断输入的是搜索内容还是URL,如果是内容,会结合默认搜索引擎来组成URL,如果是URL,会加上协议(https\http)形成完整的URL

敲入回车后,浏览器给当前页面发送一个beforeunload的事件,beforeunload事件允许页面在退出之前执行一些数据清理操作,还可以询问用户是否要离开当前页面,接着进入加载状态,如下图,此时页面内容没有变化。

img

2.URL请求过程

浏览器进程通过IPC机制把URL请求发送到网络进程,网络进程先判断本地缓存,如果有直接返回缓存,然后进行DNS解析,建立连接,发起网络请求。等待请求回来的后续处理

2.1重定向

如果响应头是301或302,需要重定向到其它URL。网络进程会从响应头的Location字段里面读取重定向的地址,然后再发起新的HTTP或者HTTPS请求,一切又重头开始了。

img

2.2 响应数据类型

Content-Type是HTTP头中一个非常重要的字段, 它告诉浏览器服务器返回的响应体数据是什么类型,不同Content-Type的后续处理流程也不同,如果是HTML,那么浏览器则会继续进行导航流程。由于Chrome的页面渲染是运行在渲染进程中的,所以接下来就需要准备渲染进程。

2.3准备渲染进程

打开一个新页面采用的渲染进程策略就是:

2.4 提交文档

网络请求由网络进程发起和接受,但是数据要由渲染进程处理,这里需要借助浏览器进程的控制,使网络进程和渲染进程进行通信。提交文档就是浏览器进程将网络进程接收到的HTML数据提交给渲染进程,如下:

img

网站通常使用图像、CSS 和 JavaScript 等外部资源。这些文件需要从网络或缓存中加载。主线程可以在解析构建DOM的过程中找到它们时一一请求,但为了加快速度,“预加载扫描器”是并发运行的。如果有喜欢的东西<img><link>在通过HTML解析器生成的标记在HTML文档中,预紧扫描器扫描并发送请求到在浏览器过程中的网线。而当解析到<seript>标签时,则会暂停HTML文档的解析,并且必须加载、解析和执行 JavaScript 代码,因为JavaScript可以通过document.write()改变整个 DOM 结构之类的东西来改变文档的形状。

如果您的 JavaScript 不使用document.write(),您可以添加asyncdefer属性到<script>标记,浏览器异步加载和运行 JavaScript 代码,并且不会阻止解析。

2.5渲染阶段

一旦文档被提交,渲染进程便开始页面解析和子资源加载,等待渲染完成后,渲染进程发消息给浏览器进程,浏览器进程完成加载动画,展示新的页面。

3.渲染流程

渲染流程就是把HTML、CSS、javas经过转化,转为页面的过程。

img

一个渲染流程会划分很多子阶段,整个处理过程叫渲染流水线,流水线可分为如下几个子阶段:构建DOM树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。每个阶段都经过输入内容 -->处理过程-->输出内容三个部分。

3.1构建DOM树

这是因为浏览器无法直接理解和使用HTML,所以需要将HTML转换为浏览器能够理解的结构——DOM树

每个DOM树的一个节点就是HTML中的一个标签,这种转化其实很常见。DOM是保存在内存中树状结构,可以通过JavaScript来查询或修改其内容。

img

3.2样式计算(Recalculate Style)

样式计算是为了计算Dom节点的每个元素的具体样式,这里就需要CSS的参与。分为三个阶段:

3.2.1 CSS转化为styleSheets

CSS样式来源主要有三种:

img

当渲染引擎接收到CSS文本时,会执行一个转换操作,将CSS文本转换为浏览器可以理解的结构——StyleSheets。这是一种结构体,渲染引擎会把所有获取到的CSS转换为styleSheets结构中的数据,并且具备了查询和修改功能,这其实是CSSDOM。

3.2.2属性值标准化

就是把CSS中的属性值,如2em、blue、bold,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。

- initial value:初始值,我们手动指定的值
- specified value:从 css、父节点、初始值来的默认值
- resolved value:给 CSSOM 用的值
- computed value:inheritance 结束后,计算出一些和布局无关的相对值,从specified value计算得来
- used value:布局计算后,确定的值
- actual value:根据运行环境的限制,然后近似计算后得到 actual value

细节概述

img

3.2.3 计算DOM元素的样式

就是把CSSDom 的数据绑定到DOM树上,通过Css的继承规则和层叠规则。CSS继承就是每个DOM节点都包含有父节点的样式,也就是所有子节点都继承了父节点样式,Chrome中的效果:

img

第二个规则是样式层叠,表示如何合并来自多个CSS源的属性值的算法。这两步最终的结果是计算每个DOM元素的具体样式,并保存在ComputedStyle的结构内。

3.3布局阶段

我们有了DOM树和DOM树种元素的样式,接着需要计算DOM树中可见元素的几何位置,整个过程叫布局。

3.3.1创建布局树

有些元素可能不会展示出来,所有创建一棵只包含可见元素的布局树,(display:none,head标签)不再该树中,但是visibility: hidden在布局树中。

img

3.3.2计算布局

上一步的布局树需要递归的计算布局,因为一个节点大小的计算通常需要先计算它的子节点的位置、大小信息等。对于布局树中的每个节点我们称为RenderObject,因为这些节点是最终需要被渲染出来的节点。

如果有样式发生变化,可视区域发生变化,产生动画,JavaScript修改样式信息,用户交互时就需要重新布局。

3.4分层

渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。正是这些图层叠加在一起构成了最终的页面图像。

layoutTree就是上边布局后形成的树,然后又会产生图层树,并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层

img

那些树会有单独的一层?

3.5图层绘制(tiles)

渲染引擎会把图层树中的每个图层进行分别绘制,并且把一个图层的绘制拆分成很多小的绘制指令,形成待绘制列表

img

从图中可以看出,绘制列表中的指令就是让其执行一个绘制操作,比如绘制粉色矩形或者黑色的线等。而绘制一个元素通常需要好几条绘制指令,因为每个元素的背景、前景、边框都需要单独的指令去绘制。所以在图层绘制阶段,输出的内容就是这些待绘制列表

3.6栅格化(raster)操作

主要操作为:

绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。你可以结合下图来看下渲染主线程和合成线程之间的关系:

img img 光栅 img img

3.7合成和显示 (draw quad)

一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。浏览器进程会处理该命令,把页面绘制到内存中,最后将内存显示在屏幕上。

img

一个完整的渲染流程大致可总结为如下:

  1. 渲染进程将HTML内容转换为能够读懂的DOM树结构。
  2. 渲染引擎将CSS样式表转化为浏览器可以理解的styleSheets(生存CSSDOM树),计算出DOM节点的样式。
  3. 创建布局树(LayoutTree),并计算元素的布局信息。
  4. 对布局树进行分层,并生成分层树(LayerTree)。
  5. 为每个图层生成绘制列表,并将其提交到合成线程。
  6. 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
  7. 合成线程发送绘制图块命令DrawQuad给浏览器进程。
  8. 浏览器进程根据DrawQuad消息生成页面,并显示到显示器上。

3.9相关概念

重排

通过JavaScript或者CSS修改元素的几何位置属性如宽高,会触发重新布局等一系列子阶段,这个过程叫重排。重排需要更新完整的渲染流水线,开销最大

img

重绘

更改元素的背景颜色,不会触发布局解决,直接进入绘制阶段等子阶段,叫重绘。重绘比重排少了布局和合成阶段,效率高一些

img

直接合成

如果你更改一个既不要布局也不要绘制的属性,渲染引擎将跳过布局和绘制,只执行后续的合成操作,我们把这个过程叫做合成,如CSS的transform来实现动画效果,在非主线程进行合成动画,合成的效率比前两者高很多。

img

4.0输入事件

事件接收

当用户在屏幕上发生触摸等手势时,浏览器进程首先接收到该手势。但是,浏览器进程只知道该手势发生的位置,因为选项卡内的内容由渲染器进程处理。因此浏览器进程将事件类型(如touchstart)及其坐标发送到渲染器进程。渲染器进程通过查找事件目标并运行附加的事件侦听器来适当地处理事件。

传递给主线程

由于运行 JavaScript 是主线程的工作,因此当页面被合成时,合成器线程将页面中附加了事件处理程序的区域标记为“非快速滚动区域”。通过拥有这些信息,如果事件发生在该区域,合成器线程可以确保将输入事件发送到主线程。如果输入事件来自该区域之外,则合成器线程继续合成新帧,而无需等待主线程。

有限的非快速滚动区域
上一篇下一篇

猜你喜欢

热点阅读