💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 从浏览器接收url到开启网络请求线程 ### 进程和线程 首先明确一下进程和线程的概念 : - 进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位) - 线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程) ### 多进程的浏览器 首先需要知道,浏览器是一个多进程的应用程序,它有一个主控进程,以及每一个tab页面都会新开一个进程(某些情况下多个tab会合并进程),除此之外,可能还包括插件进程,GPU,浏览器内核等等。 看下面一个图: :-: ![](http://xiaoyulive.oss-cn-beijing.aliyuncs.com/%E6%88%AA%E5%9B%BE/QQ%E6%88%AA%E5%9B%BE20180316100833.png) :-: ![](http://xiaoyulive.oss-cn-beijing.aliyuncs.com/%E6%88%AA%E5%9B%BE/QQ%E6%88%AA%E5%9B%BE20180316101008.png) 我打开了 Chrome 浏览器,在任务管理器中可以看到,实际上浏览器创建了多个进程。 #### 浏览器都包含哪些进程? 知道了浏览器是多进程后,再来看看它到底包含哪些进程:(为了简化理解,仅列举主要进程) 1. **Browser进程**:浏览器的主进程(负责协调、主控),只有一个。作用有 - 负责浏览器界面显示,与用户交互。如前进,后退等 - 负责各个页面的管理,创建和销毁其他进程 - 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上 - 网络资源的管理,下载等 2. **第三方插件进程**:每种类型的插件对应一个进程,仅当使用该插件时才创建 3. **GPU进程**:最多一个,用于3D绘制等 4. **浏览器渲染进程**(浏览器内核)(Renderer进程,内部是多线程的):默认每个Tab页面一个进程(有时候会优化,如多个空白tab会合并成一个进程),互不影响。主要作用为 控制页面渲染,脚本执行,事件处理 等 可以通过 Chrome 的 更多工具 -> 任务管理器 验证 : :-: ![](http://xiaoyulive.oss-cn-beijing.aliyuncs.com/%E6%88%AA%E5%9B%BE/QQ%E6%88%AA%E5%9B%BE20180316103315.png) #### 浏览器多进程的优势 相比于单进程浏览器,多进程有如下优点: - 避免单个page crash影响整个浏览器 - 避免第三方插件crash影响整个浏览器 - 多进程充分利用多核优势 - 方便使用沙盒模型隔离插件等进程,提高浏览器稳定性 简单点理解:**如果浏览器是单进程,那么某个Tab页崩溃了,就影响了整个浏览器,体验有多差;同理如果是单进程,插件崩溃了也会影响整个浏览器。** 当然,内存等资源消耗也会更大,有点空间换时间的意思。 #### 而至于多核多线程 CPU ? 在配置电脑的时候,我们经常会谈到 CPU 有多少核心,每个核心多少个线程,而浏览器同时开启如此多的进程,每个进程又开启那么多的线程,从数量上看,CPU 似乎不能负荷那么多,但实际上,CPU 是使用时间片进行分时处理,由于切分的时间间隔特别的短,作为我们普通人根本感觉不到,因此感觉到所有程序都是并行处理的,实际上,比如 4核心双线程的 CUP 同时最多只能进行 8 个工作的处理,但由于时间片切分的时间特别短,以至于我们感觉所有程序都是并行处理的。 ### 多线程的浏览器内核 每一个tab页面可以看作是浏览器内核进程,然后这个进程是多线程的,它有几大类子线程 - GUI 线程 - JS 引擎线程 - 事件触发线程 - 定时器线程 - 网络请求线程 :-: ![](http://xiaoyulive.oss-cn-beijing.aliyuncs.com/imgs/browser_inner_thread.png) 可以看到,里面的JS引擎是内核进程中的一个线程,这也是为什么常说JS引擎是单线程的。 可以这样简单的理解: 浏览器每一个进程就是一个大工厂,而进程中的每一个线程就是工厂里面干活的各种工人。 #### 重点是浏览器内核(渲染进程) 重点来了,我们可以看到,上面提到了这么多的进程,那么,对于普通的前端操作来说,最终要的是什么呢?答案是**渲染进程** 可以这样理解,页面的渲染,JS的执行,事件的循环,都在这个进程内进行。接下来重点分析这个进程 **请牢记,浏览器的渲染进程是多线程的** 终于到了线程这个概念了😭,好亲切。那么接下来看看它都包含了哪些线程(列举一些主要常驻线程): 1. GUI渲染线程 - 负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。 - 当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行 - 注意,**GUI渲染线程与JS引擎线程是互斥的**,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中**等到JS引擎空闲时**立即被执行。 2. JS引擎线程 - 也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎) - JS引擎线程负责解析Javascript脚本,运行代码。 - JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序 - 同样注意,**GUI渲染线程与JS引擎线程是互斥的**,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。 3. 事件触发线程 - 归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助) - 当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中 - 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理 - 注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行) 4. 定时触发器线程 - 传说中的`setInterval`与`setTimeout`所在线程 - 浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确) - 因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行) - 注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。 5. 异步http请求线程 - 在XMLHttpRequest在连接后是通过浏览器新开一个线程请求 - 将检测到状态变更时,如果设置有回调函数,异步线程就**产生状态变更事件**,将这个回调再放入事件队列中。再由JavaScript引擎执行。 ### 解析URL 输入URL 后,浏览器会进行解析(URL的本质就是统一资源定位符) URL一般包括几大部分: - `protocol`,协议头,譬如有http,ftp等 - `host`,主机域名或IP地址 - `port`,端口号 - `path`,目录路径 - `query`,即查询参数 - `fragment`,即`#`后的hash值,一般用来定位到某个位置 ### 网络请求都是单独的线程 每次网络请求时都需要开辟单独的线程进行,譬如如果URL解析到http协议,就会新建一个网络线程去处理资源下载 因此浏览器会根据解析出得协议,开辟一个网络线程,前往请求资源。