见微知著 - 浅述浏览器的发展历程


提到浏览器,我们想到的就是url的请求渲染流程、优化渲染性能,但是你真的知道浏览器是怎么组成的,浏览器又是怎么演变成现在的样子的呢?

一、进程和线程

先用一句话介绍一下进程和线程之间的关系

一个进程就是一个程序的实例,一个进程至少包含一个线程

一个进程中只有一个线程的称为单线程处理,一个进程由多个线程组成的称为多线程处理线程是依附于进程的,而且在进程中使用多个线程处理能够并行处理任务,提高程序效率。由于进程和线程的高耦合性,因此有着以下4个特点:

  1. 进程中任意一个线程执行出错,都会导致整个进程的崩溃。如上图,如果任务1出现了什么错误,就会导致线程1执行出错,进而使进程崩溃。

  2. 线程之间的数据可以共享 上图的进程2,任务4执行时可以任意读取任务1、2、3的执行结果,线程中的数据可以相互被读取。

  3. 当一个进程关闭之后,操作系统会回收这个进程的所有空间。当一个进程关闭之后,操作系统会回收进程所申请的所有资源,因为操作不当导致的内存泄漏,在进程关闭后这些内存也会被回收。

  4. 进程之间的内容相互隔离。进程之间的内容相互隔离是为了每一个进程之间的数据互相不会被干扰,每一个进程都有着自己的数据,避免进程之间数据被串写的情况。虽然同一个进程内的线程之间数据是可以相互读取的,但是不同进程之间的内容是不可以的。如果进程之间需要通信的话,就需要使用进程间通信(IPC)的机制了。

二、早期浏览器

了解了进程和线程后,我们来看下早期的浏览器是什么样子。在2007年前,市面上的浏览器还都是单进程的,单进程的浏览器结构如下图。从上图我们可以看到,网络、插件、JS运行环境只是一个个的线程,运行在同一个进程里。

  • 任意一个线程的崩溃都会造成整个浏览器的崩溃,造成浏览器不稳定。

  • 所有页面的JS运行环境和渲染都会运行在同一个线程(页面线程)中,这就意味着同一时刻只能运行一个模块。如果运行的脚本是一个死循环的,那么就会一直占用着线程,导致其他的模块就没有机会运行。

  • 由于浏览器的漏洞,脚本就可以通过漏洞来获取系统权限,对你的电脑做恶意的事情。

早期浏览器的各种问题,导致我们的使用变得异常的艰难。不过好在,在2008年提出了浏览的多进程架构,解决了单进程带来的问题。

三、多进程浏览器

多进程浏览器与早期的浏览器有什么区别呢?我们先来看下什么是多进程浏览器。当你打开一个页面,在浏览器的任务管理器中可以看到启动了多个进程,这就是目前的chrome系统进程架构,也就是多进程架构。一个浏览器由多个进程组成,每个模块都运行在自己的进程中,互相不干扰。目前的chrome浏览器包含:1个浏览器主进程、1个GPU进程、1个网络进程、若干个渲染进程和若干个插件进程(扩展进程)。上图是几个进程之间的通信流程,接下来我们来具体看看这几个进程的功能:

  • 浏览器进程 浏览器的主进程,主要负责整个浏览器的协调工作,界面的显示,用户的操作,以及存储管理和权限管理。

  • 渲染进程 渲染进程与我们前端的工作密切相关,主要是将HTML、CSS、JS解析转换为用户可以查看交互的页面。默认情况下,chrome会为每个tab标签创建一个渲染进程(Process-per-site-instance 模式)。渲染进程也就是浏览器内核,主要包含了以下几个线程

  1. GUI渲染线程 主要功能是解析HTML和CSS文件,生成DOM树和CSSOM,组合成渲染树,绘制在页面上。这个阶段可能会出现重排和重绘,这也是前端重要的优化点。

  2. JS引擎线程 JS引擎,chrome中也就是V8引擎,主要是负责处理执行JS。JS是单线程的,所以线程中只能执行一个任务,不能并行。这就又出现了一个经典的题目,js的执行顺序,可以做做看你能否答对~~

setTimeout(function () {
  console.log(" set1");
  new Promise(function (resolve) {
    resolve();
  }).then(function () {
    new Promise(function (resolve) {
      resolve();
    }).then(function () {
      console.log("then4");
    });
    console.log("then2 ");
  });
});
new Promise(function (resolve) {
  console.log("pr1");
  resolve();
}).then(function () {
  console.log("then1");
});
setTimeout(function () {
  console.log("set2");
});
console.log(2);
new Promise(function (resolve) {
  resolve();
}).then(function () {
  console.log("then3");
});
  1. 事件触发线程 主要是控制事件的循环,当触发click事件、setTimeout、http异步请求时,为其分配到对应的线程中,等待执行。

  2. 定时触发器线程 setTimeout和setInterval所在的线程,计时结束后就会被添加到任务队列中,等待执行

  3. 异步HTTP请求线程 在XMLHttpRequest在连接后是通过浏览器新开启的一个线程,当监测到状态改变后并且有对应的回调函数,那么这个回调函数就会被添加到任务队列中,等待执行

Chrome 有个机制,同一个域名同时最多只能建立 6 个 TCP 连接 ===>TCP队列等待

  • GPU进程 跟CPU是完全不同的东西哦,GPU是一种图形处理器。主要是为了实现3DCanvas,现在的chrome的页面也会采用GPU来绘制。GPU为元素单独绘制一个复合层,当修改样式时不影响其他的复合层。复合层之间时独立的,重排和重绘都不会相互影响,也做到了性能优化。我们用chrome测试一下,打开开发者工具 Layers

  • 网络进程 主要是负责页面的网络资源加载。

  • 插件进程 主要是负责插件的运行,每个插件都是一个进程,在插件执行的时候创建

四、改进和未来

看完上面的内容,那么多进程浏览器解决了哪些问题,又带来了什么问题呢?

改进:
  • 解决了单进程所带来的不稳定性。不同的模块在不同的进程中,进程之间互不影响。当一个页面崩溃后也不会影响其他的页面,因为使用了各自的渲染进程。

  • 解决了不安全性。在单进程中,插件和脚本都可能造成系统的不安全。通过插件可以获取操作系统的资源,当一个插件运行时,插件可以完全操作你的电脑,向你的电脑投入病毒。脚本则是可以获取你的系统权限,并对你的电脑做一些恶意的事情。

  • 多进程是将渲染进程和插件进程放进了沙箱中。沙箱就向是一道锁,在不影响进程执行的前提下,不能对系统硬盘进行写操作,也不能读取敏感数据。

问题:
  • 高资源占用。因为每一个页面都会有各自的渲染进程,因此每一个进程都会包含公共的基础结构(例如JS引擎线程)

  • 更复杂的体系架构。浏览器各模块之间耦合性高,扩展性差等问题。

未来:

为了解决这些问题,Chrome 官方团队也逐步将当前架构转为面向服务的架构。不过鉴于当前架构的复杂程度,还是需要一段时间才能完成,我们一起期待未来性能更好的浏览器。

参考资料

  • https://developers.google.com/web/updates/2018/09/inside-browser-part1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值