概述
目录
- 1. 为什么要学习浏览器工作原理?
- 2. 浏览器的进程与线程
- 2.1 并行处理
- 2.2 进程与线程
- 2.3 渲染进程的线程
- 2.4 进程与线程的关系与区别
前言:
浏览器是前端工程师必备的工具,JavaScript语言就运行在浏览器端。所以,深入理解浏览器的工作原理更能让我们深入对JavaScript的理解。此栏目文章仅用来记录学习浏览器工作原理的过程。
1. 为什么要学习浏览器工作原理?
在说浏览器的进程之前,先来说一下为什么要学习浏览器的工作原理(这部分内容整理自网络)。
(1)准确评估Web开发项目的可行性
随着web特性的极大丰富和浏览器性能的提升,越来越多的项目都可以用web来开发,所以了解浏览器是如何工作的,能够让我们更加准确的决策是否选用web来开发项目。如果我们对浏览器不了解,可能就会放弃选择web来开发项目。
(2)从更高的维度审视页面
作为一名前端开发工程师,我们需要站在用户体验角度来考虑页面的性能,下面来看几个常见的用户体验指标:
- 当用户请求一个网站时,如果在 1 秒内看不到关键内容,用户会产生任务被中断的感觉。
- 当用户点击某些按钮时,如果 100ms 内无法响应,用户会感受到延迟。
- 如果 Web 中的动画没有达到 60fps,用户会感受到动画的卡顿。
这里的页面加载时长、用户交互反馈时长、Web 动画中的帧数都决定了用户体验的流畅度,并最终决定了用户体验的效果。在这个用户体验至上的今天,解决这些问题,才能避免损失用户。
这些指标往往是一些列复杂的因素导致的,我们只有深入理解浏览器的工作原理,才能站在全局的角度定位问题或者写出高效的代码。
我们常常看到一个面试题:在浏览器地址栏输入一个URL到页面渲染完的过程,发生了什么?
这个问题就涉及到了很多浏览器的工作原理。如果我们不学习浏览器工作原理,实际上也不会影响我们业务的开发。但是,如果我们对浏览器的工作深入理解,就能更高的维度审视自己的项目,通过全视野快速定位项目中不合理的地方。最终将这些知识梳理成一个完整的知识体系,在未来的,项目开发、项目优化中都会更加得心应手了。
(3)在快节奏的技术迭代中把握本质
我们都知道,前端的知识覆盖面比较广,并且更新迭代的速度非常快。
如果了解了浏览器的工作机制,那么就可以梳理出来前端技术的发展脉络,更加深刻地理解当前的技术,同时你也会清楚其不足之处,以及演化方向。
只要把握了的前端的本质,也就不会惧怕快速的更新迭代了。
2. 浏览器的进程与线程
上面部分是整理的学习浏览器工作原理的原因,下面进入正题!
首先,可以看到,浏览器打开一个标签页,在任务管理器有四种进程:
打开任务管理器方法:菜单(浏览器右上角三个点)——更多工具——任务管理器。
2.1 并行处理
在介绍进程和线程之前,先看一下什么是并行处理,理解并行处理的概念可以让我们更容易去理解进程和线程之间的关系。
计算机中的并行处理就是同一时刻处理多个任务,比如我们要计算下面这三个表达式的值,并显示出结果。
A = 1+2
B = 20/5
C = 7*8
在编写代码的时候,我们可以把这个过程拆分为四个任务:
任务 1 是计算 A=1+2;
任务 2 是计算 B=20/5;
任务 3 是计算 C=7*8;
任务 4 是显示最后计算的结果。
正常情况下程序可以使用单线程来处理,也就是分四步按照顺序分别执行这四个任务。如果采用多线程,只需分“两步走”:第一步,使用三个线程同时执行前三个任务;第二步,再执行第四个显示任务。
通过对比分析,我们发现使用并行处理能大大提升了性能。
2.2 进程与线程
从本质上说,进程和线程都是 CPU 工作时间片的一个描述:
- 进程描述了 CPU 在运行指令及加载和保存上下文所需的时间,放在应用上来说就代表了一个程序。
- 线程是进程中的更小单位,描述了执行一段指令所需的时间。
一个进程就是一个程序的运行实例。详细解释就是,启动一个程序的时候,操作系统会为该程序创建一块内存,用来存放代码、运行中的数据和一个执行任务的主线程,我们把这样的一个运行环境叫进程。
进程是运行在虚拟内存上的,虚拟内存是用来解决用户对硬件资源的无限需求和有限的硬件资源之间的矛盾的。从操作系统角度来看,虚拟内存即交换文件;从处理器角度看,虚拟内存即虚拟地址空间。
如果程序很多时,内存可能会不够,操作系统为每个进程提供一套独立的虚拟地址空间,从而使得同一块物理内存在不同的进程中可以对应到不同或相同的虚拟地址,变相的增加了程序可以使用的内存。
对于上文中的例子,可以用下图来表示:
从图中可以看到,线程是依附于进程的,而进程中使用多线程并行处理能提升运算效率。
进程和线程之间的关系有以下四个特点:
(1)进程中的任意一线程执行出错,都会导致整个进程的崩溃。
(2)线程之间共享进程中的数据。
如下图所示,线程之间可以对进程的公共数据进行读写操作:
从上图可以看出,线程 1、线程 2、线程 3 分别把执行的结果写入 A、B、C 中,然后线程 2 继续从 A、B、C 中读取数据,用来显示执行结果。
(3)当一个进程关闭之后,操作系统会回收进程所占用的内存
当一个进程退出时,操作系统会回收该进程所申请的所有资源;即使其中任意线程因为操作不当导致内存泄漏,当进程退出时,这些内存也会被正确回收。
(4)进程之间的内容相互隔离。
进程隔离就是为了使操作系统中的进程互不干扰,每一个进程只能访问自己占有的数据,也就避免出现进程 A 写入数据到进程 B 的情况。正是因为进程之间的数据是严格隔离的,所以一个进程如果崩溃了,或者挂起了,是不会影响到其他进程的。如果进程之间需要进行数据的通信,这时候,就需要使用用于进程间通信的机制了。
说完这些,我们来看一下Chrome浏览器的架构图:
从图中可以看出,最新的 Chrome 浏览器包括:
- 1 个浏览器主进程
- 1 个 GPU 进程
- 1 个网络进程
- 多个渲染进程
- 多个插件进程
再来看一下这些进程的功能:
- 浏览器进程:主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
- 渲染进程:核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
- GPU 进程:其实, GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。
- 网络进程:主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
- 插件进程:主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
所以,打开一个网页,最少需要四个进程:1 个网络进程、1 个浏览器进程、1 个 GPU 进程以及 1 个渲染进程。如果打开的页面有运行插件的话,还需要再加上 1 个插件进程。
虽然多进程模型提升了浏览器的稳定性、流畅性和安全性,但同样不可避免地带来了一些问题:
- 更高的资源占用:因为每个进程都会包含公共基础结构的副本(如 JavaScript 运行环境),这就意味着浏览器会消耗更多的内存资源。
- 更复杂的体系架构:浏览器各模块之间耦合性高、扩展性差等问题,会导致现在的架构已经很难适应新的需求了。
2.3 渲染进程的线程
说完进程,再来重点看一下浏览器的渲染进程的线程,总共有五种:
(1)GUI渲染线程
- 负责渲染浏览器页面,解析HTML、CSS,构建DOM树、CSSOM树、渲染树和绘制页面
- 当界面需要重绘或由于某种操作引发回流时,该线程就会执行
注意:GUI渲染线程和JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
(2)JS引擎线程
- JS引擎线程也称为JS内核,负责处理Javascript脚本程序,解析Javascript脚本,运行代码;
- JS引擎线程一直等待着任务队列中任务的到来,然后加以处理,一个Tab页中无论什么时候都只有一个JS引擎线程在运行JS程序;
注意:GUI渲染线程与JS引擎线程的互斥关系,所以如果JS执行的时间过长,会造成页面的渲染不连贯,导致页面渲染加载阻塞。
(3)时间触发线程
- 属于浏览器而不是JS引擎,用来控制事件循环;
- 当JS引擎执行代码块如setTimeOut时(也可是来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件触发线程中;
- 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理;
注意:由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行);
(4)定时器触发进程
- 即setInterval与setTimeout所在线程;
- 浏览器定时计数器并不是由JS引擎计数的,因为JS引擎是单线程的,如果处于阻塞线程状态就会影响记计时的准确性;
- 因此使用单独线程来计时并触发定时器,计时完毕后,添加到事件队列中,等待JS引擎空闲后执行,所以定时器中的任务在设定的时间点不一定能够准时执行,定时器只是在指定时间点将任务添加到事件队列中;
注意:W3C在HTML标准中规定,定时器的定时时间不能小于4ms,如果是小于4ms,则默认为4ms。
(5)异步http请求线程
- XMLHttpRequest连接后通过浏览器新开一个线程请求;
- 检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将回调函数放入事件队列中,等待JS引擎空闲后执行;
2.4 进程与线程的关系与区别
最后,再来看一下进程与线程的关系与区别。
进程和线程的关系:
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
(4)处理机分给线程,即真正在处理机上运行的是线程。
(5)线程是指进程内的一个执行单元,也是进程内的可调度实体。
线程与进程的区别:
(1)根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
(2)资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
(3)包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
(4)内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
(5)影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
(6)执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行
最后
以上就是热情保温杯为你收集整理的【浏览器工作原理】浏览的进程和线程的全部内容,希望文章能够帮你解决【浏览器工作原理】浏览的进程和线程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复