浏览器的进程与线程

648 阅读4分钟

线程与进程中我们讲述了为啥需要需要进程,为啥需要线程。那么在浏览器里都有哪些进程与线程,他主要的工作是做什么?本节将从大概的讲述浏览器的线程与进程以及他们各自的作用。

在浏览器中,进程主要有以下几个:

  1. GPU进程。浏览器全局只有这么一个进程。主要是与图形渲染有关。

  2. 其他插件的进程,比如你给你浏览器装了一个插件,那么这一个插件就是一个进程。

  3. Browser进程:浏览器的主进程(负责协调、主控),只有一个。主要功能有以下:

    • 负责浏览器界面显示,与用户交互。如前进,后退等
    • 负责各个页面的管理,创建和销毁其他进程
  4. 浏览器渲染进程,也被称为浏览器内核。分类有:

    Google Chrom: Chrome 28开发版本的版本说明中还在使用WebKit,而从Chrome 28.0.1469.0后已经替换为Blink

    **Internet Explorer: Trident内核,也是俗称的IE内核

    Mozilla Firefox: Gecko内核,俗称Firefox内核。

    Safari: WebKit

    Opera: 最初是自己的Presto内核,后来是Webkit,现在是Blink内核

在以上进程中,我们最需要关心的进程是:浏览器渲染进程,他的主要作用有:负责页面的渲染,脚本执行,时间处理,网络请求等功能。

浏览器渲染进程

在一个进程中,至少有一个线程。线程被称为CPU任务调度的最小执行单位。那么在浏览器的渲染进程中,有以下几个线程:

  1. GUI渲染线程: 解析html文档,生成DOM树与CSS树(需要注意的是css树不会阻塞dom树的生成)。当生成DOM树与CSS树之后,就根据这两 个数生成一个render树(在生成render树的时候,如果有一方没有解析完毕就会等待解析完成。此时此刻是双方会互相阻塞),然后将这个render树渲染到界面上。

  2. JS线程:用来执行JS代码。具体执行过程详见JS运行过程详解

  3. 定时器线程:用来处理定时器线程,当定时器到期的时候,将回调放到任务队列里面,等待JS线程的执行。那么有了JS线程,我们为啥还需要定时器线程呢?看下面代码解释:

    function test() {
      setTimeout(() => {
      console.log('我是计时器1');
    }, 1000);
      setTimeout(() => {
          console.log('我是计时器2');
    }, 2000);
      
    };
    test();
    

    假如没有定时器线程,又因为JS是单线程的,我只能一个一个的压入栈中执行,那么首先是计时器1入栈,接着是计时器2入栈。但是因为计时器1的时间小于计时器2的时间,那么应该计时器1首先出栈。但是因为栈是一个先进后出的数据结构。那么这就与栈的定义发生了冲突。因为计时器2还没有到时间,没有出栈,所以计时器1也就不能出栈。

  4. 事件触发线程。用来管理事件的触发,例如:点击事件,鼠标移动事件。当这些个事件被触发的时候,就会将这些事件的回调添加到任务队列里,等待JS执行。

  5. 异步HTTP请求线程。在XMLHttpRequest在连接后新启动的一个线程,线程如果检测到请求的状态变更,如果设置有回调函数,该线程会把回调函数添加到事件队列,同理,等待JS引擎空闲了执行。

JS线程与GUI线程互斥的原因

主要是因为当一个文档在加载的时候,如果此时JS线程也在加载执行,例如要获取一个id为demo1的节点,此时此刻我们渲染过程中,还并没有生成render树,也就不会进行布局和渲染。那么此时这个节点是没有的,那么肯定就会找不到。因此为了避免这种情况的发生,在浏览器中,JS线层和GUI线程是互斥的,当一个执行的时候,另外一个就会被强制挂起。这样就会导致一个问题,当JS执行一个时间复杂度非常高的算法的时候,因为迟迟不能执行完毕,导致GUI渲染线程被挂起太久,就会导致页面看起来卡顿,事件响应变慢。解决办法,可以通过Web Worker解决。