浏览器运行机制总结
前言
本篇文章主要是为帮助于前端开发者了解开发之外又与开发息息相关的知识。
这里所讲的浏览器多指chromium浏览器,其实其他浏览器也大致相同。
笔者的几句话:本人也是个刚从事前端3年的菜鸟,文中有任何错误不对的地方望大佬海涵,如能指点一番,更是不甚感激。
文中大多内容都是我参考了很多文章,以及问了业界相关的一些大佬整合下来的,其中会引用一些个人认为比较比较好以及易于前端开发者理解的部分,并且我会尽量把所有的文章放至底部一并供大家参考。
一、从进程的角度简单了解一下浏览器
1.多进程的浏览器
在讲结构之前,还有一些必须要了解的知识。
现代浏览器很多都支持多进程模型,这个模型能有效的预防浏览器的其中一个页面崩溃而不影响其他页面,同时也很复杂,也加大了资源的消耗,你可以尝试运行下方代码在当前页面的控制台,就可以看出当前页面崩溃而不会影响其他页面。
for(let i =0;i<10;i--){console.log('123456789')}
2.了解多进程
那么既然是多进程模型,那么哪几个进程呢,我在下方列举这5个主要的进程,本文也是根据这5个进程一步步进行讲解
浏览器进程
负责浏览器界面的显示,各个页面的管理,其他各种进程的管理GPU进程
最多只有一个,当且仅当GPU硬件加速打开的时候才会被创建,主要用于对3D加速调用的实现网络进程
负责页面的网络资源加载,很多文章写的都是不存在这个进程的,我还有点迷惑,其实是网络这一块之前是浏览器主进程负责的,后来独立了出来。渲染进程
这里下面要重点讲,与我们开发息息相关的运行在沙箱的进程,它主要负责HTML解析,CSS解析,布局,和javascript的支持。上面所讲的死循环导致的进程崩溃也就是这个进程崩溃掉了。插件进程
每种类型的插件对应一个进程,仅当使用该插件时才创建。
通常情况下打开2个页面会有5个进程,分别是:浏览器主进程、GPU进程、网络进程和2个渲染进程,也会有一些其他情况存在。
- 如果页面中有插件,插件也需要一个单独的进程。
- 如果页面中有 iframe,iframe 也会运行在单独的进程中。
- 如果你装了扩展,扩展也会占用进程。
- 如果两个页面属于同一个站点,并且 B 页面是从 A 页面中打开的,那么他们会共用一个渲染进程。
3.总结
看到这里,你应该对浏览器运行的机制有了一个大概了解,最起码你应该知道了为什么页面崩溃不会导致整个浏览器崩溃的原因,以及与我们开发息息相关的html,css,js是由哪一部分去解析执行的。
二、从输入url到浏览器到页面的过程
1.浏览器进程对URL进行初步的处理
用户输入URL确认后,浏览器进程
会检查输入内容是否符合URL规则,不符合会将输入内容当成搜索内容拼接到浏览器的默认搜索引擎,符合URL规则将通过进程间通信(IPC)将请求发送给网络进程
,此时导航栏会处于onbeforeunload状态(加载状态),页面还未重载,这是因为要等渲染进程
向浏览器进程
进行确认,浏览器才会更新页面。
2.网络进程接收到URL进行处理
网络进程拿到URL后首先会查看是否有缓存内容,如果有且没有过期,会直接返回缓存内容,缓存的时间很短,也和浏览器的设置有关。
如果没有缓存,网络进程会进行DNS解析,意思就是要找到我们要访问的IP,这是一个递归的过程,会从下方这几个地方进行查找直到找到为至。
- 首先会从浏览器的DNS缓存种查找是否有我们要访问的IP
- 系统自身的DNS缓存
- 尝试读取hosts文件
- 如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DNS服务器)发起域名解析请求。
- 运营商的DNS服务器首先查找自身的缓存,找到对应的条目,且没有过期,则解析成功。如果没有找到对应的条目,则有运营商的DNS代我们进行这个类似的递归操作,直到找到为止。
3.进行网络请求
这里比较复杂,很多文章会讲述关于TCP三次握手四次挥手以及向下传输来回的过程,这里实际上与浏览器的机制关系不大了,所以我这里就不去细讲了,就把大概的流程放到下面,感兴趣的朋友可以去专门学习下。
- 进入TCP队列,同一个域名同时最多只能建立 6 个TCP 连接,如果在同一个域名下同时有 10 个请求发生,那么其中 4 个请求会进入排队等待状态
- 创建 TCP 连接(三次握手)
- 如果是HTTPS请求会建立 TLS 连接(client hello, server hello, pre-master key 生成『对话密钥』);
- 发送 HTTP 请求(请求行[方法、URL、协议]、请求头 Cookie 等、请求体 POST)
- 接受请求(响应行[协议、状态码、状态消息]、响应头、响应体等)
- 如果状态码是301或302,根据响应头中的 Location 重定向
- 状态码 200,根据响应头中的 Content-Type 决定如何响应并交给相应的进程,如下载文件交给
下载管理器
,加载资源、渲染 HTML将通知浏览器进程
进行预渲染工作。
4.浏览器进程进行预渲染工作
浏览器进程会根据数据判断是否同一站点(相同的协议和根域名),决定是否重新创建新的进程,如果是同一站点就会复用同一站点的渲染进程。
如果不是同一站点,浏览器进程会向渲染进程发送提交文档消息,渲染进程收到提交文档消息后,与网络进程建立传输数据管道,渲染进程接收数据完毕后会象浏览器进程提交确认提交的消息。浏览器接收确认提交消息后,会移除旧文档、更新界面、地址栏,导航历史状态等,这个时候导航栏有个小动作很有意思,就是loading本来是顺时针旋转的,在这之后会变成逆时针旋转,同时这也代表了渲染进程进行工作了。
5.渲染进程进行工作
渲染引擎渲染文档完成后向至浏览器进程提交,这是一个非常重要且复杂的部分,在第三部分>渲染引擎的工作原理重点讲了渲染进程接收到文档后是如何进行工作的。
三、渲染引擎的工作原理
1.主要模块介绍
渲染引擎主要有这么几个模块,HTML解析器
,css解析器
,js引擎
,布局模块
和绘图模块
,这里大致介绍一下每个模块负责的内容。
- HTML解析主要负责解析将文档解析为dom树
- css解析器主要负责将css内容解析为浏览器能够识别的css sheets
- js引擎就是解析执行js内容
- 布局模块结算每个元素、节点的位置大小等信息
- 绘图模块拿到计算好的数据绘制页面
2.工作流程
渲染引擎工作是从上至下的逐行解析,首先由HTML解析器
进行解析整个文档逐步生成dom树
和render树,其中遇到外部的将会调用css解析器
构建css树,js同理(没有树)。但是如果行内css则直接解析,一般情况下解析工作是非阻塞的,除非遇到js,js的执行与下载均会造成html解析的阻塞,但css不会,css只会阻塞渲染而不影响解析,css解析器和js引擎是互斥的,他们不会同步进行。
生成完render树之后交于布局模块进行计算各个元素,节点的位置大小等信息,后绘图模块进行绘制渲染到页面。
通常这个流程是重复执行的,因为在实际应用过程中会产生交互或其他原因导致页面的重绘与回流。
四、参考文章如下(不分先后)
理解WebKit和Chromium: Chromium多进程模型
进程、线程与页面渲染的关系
从输入URL到页面加载发生了什么
HTTP响应头和请求头信息对照表
html的解析流程
DOM、DOM树和DOM的其他几个概念
Render树与CSS解析