进程和线程是什么?

进程

进程是cpu分配资源(比如分配内存)的最小单位。一个应用程序就是一个进程,也可能对应多个进程。比如浏览器就是多个进程的。
image.png

进程的特点

进程就相当于一个工厂。他能相对独立的完成某项工作。比如说,我们使用微信可以进行实时通信。这就是微信这个进程完成的任务。

  1. 它有自己可支配的内存空间。(cpu分配) 相当于工厂有自己的厂区。
  2. 它是由一个线程或多个线程组成的。线程就像是工厂内的工人,真正完成具体某项工作的人。
  3. 进程之间相互独立。类比于工厂之间相对独立。
  4. 各个线程之间共享进程的内存区域,共同协助完成进程的任务。相当于工厂工人相互配合共同达成工厂的业绩目标。

    线程

    线程是cpu调度的最小单位。
    所谓调度,就是分配任务。线程是接收具体任务的,各线程分工合作完成进程的工作目标。

    浏览器的多进程

    浏览器这个应用程序是存在多个进程的。打开设置=>更多工具=>任务管理器我们能看到浏览器本身存在很多进程。
    image.png

  5. Browser进程浏览器应用的主进程,只有一个。负责整个浏览器应用的管理和调控。

    1. 负责浏览器界面的显示和交互。前进后退,刷新等。
    2. 负责标签页的销毁和创建等。
  6. 第三方插件进程。第一个第三方插件对应一个进程。

image.png

  1. GPU进程。最多一个,用于3D绘制。
  2. 浏览器渲染进程。(浏览器内核)。(Renderer进程,内部是多线程的),一个tab页对应一个进程。互不影响。

    浏览器多进程的优势

  3. 充分利用cpu多核的特性。

  4. 避免某个进程死机,导致整个浏览器都宕机。比如说,第三方插件崩溃,某个页面崩溃。

    浏览器内核(Renderer进程)

    我们前面提到,浏览器进程是多线程的。他们共同完成页面的渲染以及与用户的交互。他们存在哪些线程呢?

  5. GUI渲染线程。负责页面的渲染绘制。

    1. 解析HTML,生成DOM树。
    2. 解析CSS,生成CSSOM树。
    3. 两者结合,生成Render树。
    4. 元素布局。
    5. 元素绘制。 :::tips
  6. 当页面需要进行重绘或者回流的时候,这个线程是要开始运行的。

  7. GUI渲染线程和JS引擎线程是互斥的,当JS引擎线程处于活跃状态的时候,GUI渲染线程处于挂起状态,实际上是被冻结的。GUI的更新会保存在一个队列中,等待JS引擎完成一次事件循环(也就是一次**tick**)后,然后在执行GUI更新。 :::

  8. JS引擎线程。也称JS内核。chrome浏览器中的JS内核就是V8引擎。负责的任务很简单,就是处理**javascript**代码。可见我们JS是单线程的。

    JS引擎线程和GUI引擎互斥。如果JS引擎运行时间过长的话,就会导致渲染过慢,导致页面卡顿。

  9. 事件触发线程。就是它负责浏览器的事件循环。实际上,很重要的一点是,事件循环并不是JS引擎在维护,而是浏览器内核在维护。事件循环在浏览器中也是**HTML**的规范,并不是**ECMAScript**的规范。 :::tips 当遇到例如setTimeout,事件监听和XHR请求的时候,它就会把相应的任务添加到该线程中。这个线程维护了一个任务队列(tasks queue),当任务满足执行条件的时候,它就会将对应的回调函数插入到任务队列的尾部,等待JS引擎的执行。 :::

  10. 定时触发器线程。用于我们的定时任务:setTimeoutsetInterval等。计时器的计时工作并不是JS引擎来完成的。而是通过该线程来完成的。当计时的时候就会通知事件触发线程将我们的回调函数移入任务队列。

  11. HTTP请求线程。XMLHttpRequest对象在建立连接之后,会开辟一个线程进行网络请求。监听XHR对象的状态改变,当状态改变的时候,将回调函数移入事件触发线程的任务队列(tasks queue)中等待JS引擎执行。

    GUI渲染线程和JS引擎互斥

    因为JS引擎可以操作DOM,如果一般操作DOM一边渲染DOM的话就会导致一些不可预知的结果。处于这个原因,所以这两个引擎是互斥的。所以如果JS执行时间过长就会导致页面加载阻塞。

    JS的单线程

    只有一个JS引擎线程解析JavaScript代码。如果存在巨量运算的话,那么JS就会耗费很多时间去计算,从而造成页面的卡顿。
    JS如何处理巨量的运算呢?
    HTML5规范中提出了web worker的概念。

    就是说,面对巨量运算的时候,JS引擎会申请一个Web worker的子线程帮助JS引擎去进行巨量运算,但是这个子线程无法操作DOM,运算结束后将结果传递给主线程。两者之间通过postMessage进行通信。