浏览器原理入门(1)
Chrome架构
进程和线程
- 进程是资源分配的最⼩单位,线程是程序执⾏的最⼩单位(资源调度的最⼩单位)
- 进程有⾃⼰的独⽴地址空间,每启动⼀个进程,系统就会为它分配地址空间,建⽴数据表来维护代 码段、堆栈段和数据段,这种操作⾮常昂贵。
- ⽽线程是共享进程中的数据的,使⽤相同的地址空间,因此CPU切换⼀个线程的花费远⽐进程要⼩ 很多,同时创建⼀个线程的开销也⽐进程要⼩很多。
- 线程之间的通信更⽅便,同⼀进程下的线程共享全局变量、静态变量等数据,⽽进程之间的通信需 要以通信的⽅式(IPC)进⾏。不过如何处理好同步与互斥是编写多线程程序的难点。
- 但是多进程程序更健壮,多线程程序只要有⼀个线程死掉,整个进程也死掉了,⽽⼀个进程死掉并 不会对另外⼀个进程造成影响,因为进程有⾃⼰独⽴的地址空间
单进程浏览器:不稳定、不流畅、不安全。 多进程浏览器:
- 浏览器进程:负责用户交互、子进程管理和文件存储等功能。
- 渲染进程:从网络下载HTML、JavaScript、CSS、图片等资源解析文可以显示和交互的页面(沙箱环境)。
- 网络进程:面向渲染进程和浏览器进程等提供网络下载功能。
- GPU进程
- 插件进程

前端网络
重要性:性能
TCP/IP
计算机的地址被称为IP地址,访问任何网站实际上只是你的计算机向另外一台计算机请求信息。
- IP:把数据包送达目的主机
- UDP:把数据包送到应用程序,不能保证数据可靠性,但是传输速度却非常快
- TCP:把数据完整地送达应用程序,是一种面向连接的、可靠地、基于字节流的传输层通信协议。

HTTP请求流程
HTTP协议,正是建立在TCP连接基础之上的。HTTP是一种允许浏览器向服务器获取资源的协议,是web的基础,是浏览器使用最广的协议。
- 构建请求
GET /index.html HTTP1.1 - 查找缓存:强缓存和协商缓存(304)
- 准备IP地址和端口:DNS
- 等待TCP队列:同一个域名同事最多只能建立6个TCP连接
- 建立TCP连接
- 发送HTTP请求:请求行、请求头、请求体
- 服务器处理HTTP请求流程后返回请求:响应行(状态码)、响应头、响应体
- 断开连接(Keep-Alive)
HTTP发展
超文本传输协议HTTP/0.9
只有一个请求行,并没有请求头和请求体,服务器没有返回头信息,服务器端并不需要告诉客户端太多信息,只需要返回数据就可以了,因为都是HTML格式的文件,内容是以ASCII字符流来传输。
浏览器推动的HTTP/1.0
- 请求头和响应头:支持文件类型、压缩、语言版本、编码类型
- 引入状态码
- 提供了Cache机制
- 加入了用户代理字段
HTTP/1.1
- 增加了持久连接:一个TCP连接上可以传输多个HTTP请求。
- 不成熟的HTTP管线化:TCP队头阻塞
- 提供了虚拟主机的支持:增加了Host字段标识当前的域名地址
- 动态生成的内容提供了完美支持:Chunk transfer机制(Bigpipe)
- Cookie、安全机制 HTTP/1.1为网络效率做了大量的优化,最核心的有如下三种方式:
- 增加了持久连接
- 浏览器为每个域名最多同时维护6个TCP持久连接
- 使用CND的实现域名分片机制

HTTP1.1的主要问题:
- HTTP/1.1对带宽的利用率却并不理想
- TCP的慢启动
- 同时开启多条TCP连接,那么这些连接会竞争固定的带宽。
- HTTP/1.1队头阻塞的问题
HTTP/2.0
一个域名只使用一个TCP长链接来消除队头阻塞问题。

多路复用机制
- 可以设置请求的优先级
- 服务器推送
- 头部压缩
HTTP/3.0
队头阻塞问题:虽然HTTP/2解决了应⽤层⾯的队头阻塞问题,不过和HTTP/1.1⼀样,HTTP/2依然是基于TCP协议的⽽TCP最初就是为了单连接⽽设计的。你可以把TCP连接看成是两台计算机之前的⼀个虚拟管道,计算机的⼀端将要传输的数据按照顺序放⼊管道,最终数据会以相同的顺序出现在管道的另外⼀头。

TCP传输过程中,由于单个数据包的丢失而造成的阻塞称为TCP上的队头阻塞。

当系统达到2%的丢包率是,HTTP/1.1的传输效率反而比HTTP/2表现的更好。
- TCP建立连接的延时:需要划掉3~4个RTT(Round Trip Time)
- TCP协议僵化
基于UDP的QUIC协议:
- 实现类似TCP的流量控制、传输可靠性的功能
- 集成了TLS加密功能
- 实现了快速握手功能
- 实现了HTTP/2中的多路复用功能

HTTP/3是个完美的协议,从⽬前的情况来看,服务器和浏览器端都没有对HTTP/3提供⽐较完整的⽀持。系统内核对UDP的优化远远没有达到TCP的优化程度,部署HTTP/3也存在着⾮常⼤的问题,中间设备僵化的问题。
浏览器请求流程
在浏览器输入URL到页面展示,中间的流程。
导航

首先浏览器进程接收到用户输入的URL请求,浏览器进程便将该URL转发给网络进程。然后在网络进程中发起真正的URL请求,接着网络进程接收到了响应头数据,便解析响应头数据,并将数据转发给浏览器进程。浏览器进程接收到网络进程的响应头数据之后,发送“提交导航(CommitNavigation)”消息到渲染进程。渲染进程接收到“提交导航”的消息之后,变开始准备接收HTML数据,接收数据的方式是直接和网络进程建立数据管道。最后渲染进程回像浏览器进程“确认提交”,这是告诉浏览器进程:“已经准备好接受和鸡西页面数据了”。浏览器进程接收到渲染进程“提交文档”的消息后,便开始移除之前旧的文档,然后更新浏览器进程中页面状态。
渲染

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

样式计算(继承、层叠)

当渲染引擎接收到CSS文本时,会执行一个转换操作,将CSS文本转换为浏览器可以理解的结构---styleSheets(document.styleSheets)。转换样式表中的属性值,使其标准化:

计算DOM树种每个节点的具体样式:
布局阶段
现在已经有了DOM树和DOM树中元素的样式,但这还不足以显示页面,因为还不知道DOM元素的集合位置信息,那么接下来就需要计算DOM树种可见元素的几何位置。
分层、绘制
渲染引擎需要为特定的节点生成专用的图层,并生成一颗对应的图层树(LayerTree)。

不是每个布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。
分块、光栅化
绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。合成线程会将图层划分为图块(tile)合成线程会按照视口附近的图块来优先生产位图,实际生成位图的操作由栅格化来执行的。所谓栅格化,是将图块转换为位图。
合成和显示
一旦所有的图块都被光栅化,合成线程就会生成一个绘制图块的命令--“DrawQuad”,然后将该命令提交给浏览器进程,浏览器进程里面有一个叫viz的组件,用来接收合成线程发送过来的DrawQuad命令,然后根据DrawQuad命令,将其页面内容绘制到内存中,最后再将内存中的信息显示在屏幕上。
- 渲染进程将HTML内容转换为能够读懂的DOM树结构
- 渲染疫情将CSS样式表转换为浏览器可以理解的styleSheets,计算出DOM节点的样式
- 创建布局树,并计算元素的布局信息
- 对布局树进行分层,并生成分层树
- 为每个图层生成绘制列表,并将其提交给合成线程
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图
- 合成线程发送绘制图块命令DrawQuad给浏览器进程
- 浏览器进程根据DrawQuad消息生成页面,并显示到显示器上。