一、常用Chrome架构
Chrome 打开一个页面需要启动多少进程?你可以点击 Chrome 浏览器右上角的“选项”菜单,选择“更多工具”子菜单,点击“任务管理器”查看
相关概念
并行处理:同一时刻处理多个任务**(多线程,大大提升性能)
线程VS进程:1、线程是不能单独存在的,它是由进程来启动和管理的2、启动一个程序的时候,操作系统会为该程序创建一块内存,用来存放代码、运行中的数据和一个执行任务的主线程,我们把这样的一个运行环境叫进程。
线程是依附于进程的,而进程中使用多线程并行处理能提升运算效率。
- 进程中的任意一线程执行出错,都会导致整个进程的崩溃。
- 线程之间共享进程中的数据。
- 当一个进程关闭之后,操作系统会回收进程所占用的内存。
- 进程之间的内容相互隔离。采用进程间通信(IPC)的机制。
单进程浏览器是指浏览器的所有功能模块都是运行在同一个进程里,这些模块包含了网络、插件、JavaScript运行环境、渲染引擎和页面等。使用单进程浏览器会带来以下三个原因:
- 不稳定
- 不流畅
- 不安全
Chrome进程架构(多线程)
从图中可以看出,最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程。
下面我们来逐个分析下这几个进程的功能。
- 浏览器进程。主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
- 渲染进程。核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
- GPU 进程。而GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘。
- 网络进程。主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
- 插件进程。主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
在多线程模型提升浏览器的稳定性、流畅性、安全性之外也带来了:
- 更高的资源占用。(消耗内存)
- 更复杂的体系架构。(浏览器各模块之间耦合性高、扩展性差)
探索未来面向服务的架构
二、TCP协议,保证页面文件能被完整送达浏览器
衡量Web页面性能的时候有一个重要指标叫:“FP”指从页面加载到首次开始绘制的时长。影响FP指标:网络加载速度。
HTTPWebSocket都是基于TCP/IP的,TCP/IP是优化Web页面的加载速度的根基。
如何保证页面文件能被完整地送达到浏览器呢?
站在数据包的视角
2、UDP:把数据包送达应用程序,因为IP是非常底层的协议,只负责把数据包传送到对方电脑,但是对方电脑并不知道把数据包交给哪个程序,因此,需要基于IP之上开发能和应用打交道的协议,常见的“用户数据包协议”称为UDP。
IP通过IP地址信息把数据包发送到指定的电脑,而UDP通过端口把数据包分发给正确程序。
使用UDP会产生那些问题:
- 1、UDP发送数据时因各种因素会有丢包现象,且不提供重发机制,所以不能保证数据可靠性。
- 2、UDP传输速度非常快,所以UDP会应用在一些关注速度、但不那么严格要求数据完整的领域,如在线视频、互动游戏等。
为了解决UDP数据包传输过程容易丢失,引入TCP。
TCP:把数据完整地送达应用程序,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP两个特点:
- 1、对于数据包丢失的情况,TCP提供重传机制;
- 2、TCP引入数据包排序机制,用来保证把乱序的数据包组合成一个完整的文件。
完整的TCP连接的生命周期包括:
- 1、建立连接
- 2、传输数据
- 3、断开连接
TCP为了保证数据传输的可靠性(通过TCP头保证了一块大的数据传输),牺牲了数据包的传输速度,因为“三次握手”和“数据包校验机制”等把传输过程的数据包数量提高了一倍。
三、HTTP请求流程,很多站点第二次打开速度会很快?
HTTP协议,是建立在TCP连接的基础上的(HTTP应用层,TCP传输层)。HTTP是一种允许浏览器向服务器获取资源的协议,是Web基础。
为什么很多站点第二次打开速度会很快?这一切都隐藏在HTTP请求中。
浏览器端发起HTTP请求流程:
- 1、构建请求行信息,构建好后,浏览器准备发起网络请求。
- 2、查找缓存。
在真正发起网络请求之前,浏览器会先在浏览器缓存中查询是否要请求的文件。其中,浏览器缓存是一种在本地保存资源副本,以供下次请求时直接使用的技术。发起网络请求——浏览器缓存已存副本——拦截请求——返回该资源副本——结束请求(不会重新去服务器下载资源)
这样做的好处:1、缓解服务器端压力,提升性能(获取资源耗时更短)2、对网站来说,缓存是实现快速资源加载的重要组成部分。
- 3、准备IP地址和端口
HTTP网络请求的第一步是和服务器建立TCP连接,建立TCP连接第一步准备IP地址和端口号(HTTP默认80,HTTPS默认443)。DNS数据缓存服务,对域名解析以供下次直接使用,这样会减少一次网络请求。
- 4、等待TCP队列
Chrome有个机制,同一个域名同时最多只能建立6个TCP连接,如果在同一个域名下同时有10个请求发生,那么4个请求会进入排队等待状态,直至进行中请求完成。
- 5、建立TCP连接
- 6、发送HTTP请求(请求行、请求头、请求体(数据))Get跟post方法
服务器端处理浏览器端发送过来的HTTP请求
- 1、返回请求(成功状态码200,没找到页面404,响应行、响应头、响应体)
- 2、断开连接(服务器向客户端返回请求数据,关闭TCP连接)
- 3、重定向
页面二次打开会很快?
- 1、DNS缓存
- 2、页面资源缓存
DNS缓存:浏览器本地IP和域名关联起来
页面资源缓存:响应头Cache-Control字段来设置是否缓存该资源。时长是Max-age参数设置。
Cache-Control:Max-age=2000
若缓存资源过期则会继续发起请求。
很多网站第二次访问能够秒开,是因为这些网站把很多资源都缓存在了本地,浏览器缓存直接使用本地副本来回应请求,而不会产生真实的网络请求,从而节省了时间。同时,DNS 数据也被浏览器缓存了,这又省去了 DNS 查询环节。
如何保持登录状态?
四、从输入URL到页面展示经历什么?
整个过程需要各个进程之间的配合:
- 浏览器进程:主要负责用户交互、子进程管理和文件储存等功能。
- 网络进程:是面向渲染进程和浏览器进程等提供网络下载功能。
- 渲染进程:主要职责是把从网络下载的HTML、JavaScript、CSS、图片等资源解析为可以显示和交互的页面。因为渲染进程所有的内容都是通过网络获取的,会存在一些恶意代码利用浏览器漏洞对系统进行攻击,所以运行在渲染进程里面的代码是不被信任的。这也是为什么 Chrome 会让渲染进程运行在安全沙箱里,就是为了保证系统的安全。
不考虑用户输入搜索关键字的情况:
1、用户输入url并回车
2、浏览器进程检查url,组装协议,构成完整的url
3、浏览器进程通过进程间通信(IPC)把url请求发送给网络进程
4、网络进程接收到url请求后检查本地缓存是否缓存了该请求资源,如果有则将该资源返回给浏览器进程
5、如果没有,网络进程向web服务器发起http请求(网络请求),请求流程如下:
5.1 进行DNS解析,获取服务器ip地址,端口(http端口默认80,https默认443)
5.2 利用ip地址和服务器建立tcp连接
5.3 构建请求头信息
5.4 发送请求头信息
5.5 服务器响应后,网络进程接收响应头和响应信息,并解析响应内容
6、网络进程解析响应流程;
6.1 检查状态码,如果是301/302,则需要重定向,从Location自动中读取地址,重新进行第4步。 301资源被永久移除 ,302资源还在。
6.2 200响应处理:
检查响应类型Content-Type,如果是字节流类型,则将该请求提交给下载管理器,该导航流程结束,不再进行
后续的渲染,如果是html则通知浏览器进程准备渲染进程准备进行渲染。
7、准备渲染进程
7.1 浏览器进程检查当前url是否和之前打开的渲染进程根域名是否相同,如果相同,则复用原来的进程,如果不同,则开启新的渲染进程
8、传输数据、更新状态
8.1 渲染进程准备好后,浏览器向渲染进程发起“提交文档”的消息,渲染进程接收到消息和网络进程建立传输数据的“管道”
8.2 渲染进程接收完数据后,向浏览器发送“确认提交”
8.3 浏览器进程接收到确认消息后更新浏览器界面状态:安全、地址栏url、前进后退的历史状态、更新web页面。
9、渲染进程对文档进行页面解析和子资源加载,HTML 通过HTM 解析器转成DOM Tree
(二叉树类似结构的东西),CSS按照CSS规则和CSS解释器转成CSSOM TREE,两个tree结合,
形成rendertree(不包含HTML的具体元素和元素要画的具体位置),
通过Layout可以计算出每个元素具体的宽高颜色位置,结合起来,开始绘制,最后显示在屏幕中新页面显示出来
五、渲染流程:HTML、CSS、JavaScript是如何变成页面?
渲染机制过于复杂,所以渲染模块在执行过程中会被划分为很多子阶段,输入的 HTML 经过这些子阶段,最后输出像素。我们把这样的一个处理流程叫做渲染流水线。
从 HTML 到 DOM、样式计算、布局、图层、绘制、光栅化、合成和显示
- DOM树:渲染进程将 HTML 内容转换为能够读懂的DOM 树结构。
- 样式计算:渲染引擎将 CSS 样式表转化为浏览器可以理解的styleSheets,计算出 DOM 节点的样式。
- 布局树:创建布局树,并计算元素的布局信息。
- 分层:对布局树进行分层,并生成分层树。
- 绘制:为每个图层生成绘制列表,并将其提交到合成线程。
- 光栅化:合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成:合成线程发送绘制图块命令DrawQuad给浏览器进程。
- 显示:浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。
重排:如果你通过 JavaScript 或者 CSS 修改元素的几何位置属性,例如改变元素的宽度、高度等,那么浏览器会触发重新布局,解析之后的一系列子阶段,这个过程就叫重排。无疑,重排需要更新完整的渲染流水线,所以开销也是最大的。
重绘:如果修改了元素的背景颜色,那么布局阶段将不会被执行,因为并没有引起几何位置的变换,所以就直接进入了绘制阶段,然后执行之后的一系列子阶段,这个过程就叫重绘。相较于重排操作,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。
合成:如果你更改一个既不要布局也不要绘制的属性,会发生什么变化呢?渲染引擎将跳过布局和绘制,只执行后续的合成操作,我们把这个过程叫做合成。
减少重排重绘, 方法很多:
- 使用 class 操作样式,而不是频繁操作 style
- 避免使用 table 布局
- 批量dom 操作,例如 createDocumentFragment,或者使用框架,例如 React
- Debounce window resize 事件
- 对 dom 属性的读写要分离
- will-change: transform 做优化。
课程地址