1. 进程(Process)
通俗解释:
-
进程可以看作是一个正在运行的程序的实例。每个进程都有自己的内存空间、数据和资源。
-
想象一下,进程就像是一个独立的办公室,里面有自己的桌子、文件和员工。每个办公室(进程)之间是相互隔离的,不能直接访问对方的文件。
在浏览器中的应用:
-
浏览器通常会为每个打开的标签页创建一个独立的进程。这意味着每个标签页都在自己的“办公室”中运行,互不干扰。
-
这种设计提高了安全性和稳定性:如果一个标签页崩溃,其他标签页仍然可以正常工作。
2. 线程(Thread)
通俗解释:
-
线程是进程中的一个执行单元。一个进程可以包含多个线程,这些线程共享进程的资源(如内存)。
-
想象一下,线程就像是办公室里的员工,他们共享同一张桌子和文件,但每个员工(线程)可以独立工作。
在浏览器中的应用:
-
在浏览器中,主线程负责处理用户界面(UI)和事件(如点击、输入等)。
-
其他线程(如 Web Worker)可以在后台执行任务,而不会阻塞主线程。这意味着用户界面可以保持响应,即使在执行复杂的计算时。
进程和线程之间的关系
-
进程和进程之间隔离,一个进程崩溃不会影响其他进程
-
一个进程可以并发多个线程,每个线程执行不同的任务
-
进程与进程之间需要传递数据需要通过进程通信管道IPC传递
-
共享内存空间:同一进程中的所有线程共享进程的地址空间,包括全局变量、堆内存等。
-
一个进程中任意一个线程执行出错,会导致这个进程崩溃
所以js(线程)执行报错时导致整个渲染进程停止工作
- 当一个进程关闭后,操作系统会回收该进程的内存空间
Chrome打开页面有哪些进程和线程
- 浏览器进程:这是 Chrome 的主进程,负责管理用户界面、标签页、地址栏、书签等。所有的用户交互和浏览器的核心功能都在这个进程中运行。
- 渲染进程:每个打开的标签页通常会有一个独立的渲染进程。渲染进程负责解析 HTML、CSS 和 JavaScript,渲染页面内容。这样做的好处是,如果一个标签页崩溃,其他标签页仍然可以正常工作。
- GPU 进程:Chrome 还可能启动一个 GPU 进程,用于处理图形渲染和加速。
- 扩展进程:如果您安装了 Chrome 扩展程序,每个扩展可能会在自己的进程中运行。这有助于提高安全性和稳定性。
- 插件进程:如果您使用了 NPAPI 插件(如 Adobe Flash),这些插件通常会在单独的进程中运行。
如果后续打开新的标签页,浏览器进程和GPU进程是共享的,默认情况是为每个标签生成一个渲染进程,如果是同一站点的话,就共用一个渲染进程。
渲染进程中的线程
-
主线程(Main Thread) :
- 负责处理DOM解析、样式计算、布局、绘制、JavaScript执行等核心任务。
- 也处理用户输入事件(如点击、滚动)。
-
GUI渲染线程(GUI THread)
- 负责渲染页面,解析html、css、构建DOM树、CSS树、render树、重排重绘
-
合成线程(Compositor Thread) :
- 负责将页面分成多个图层(Layer),并合成最终图像。
- 独立于主线程,提升滚动和动画的流畅性。
-
光栅化线程(Raster Thread) :
- 将图层转换为位图(Rasterization),通常在GPU上执行。
- 多个光栅化线程可并行处理不同图层的位图生成。
-
JavaScript引擎线程:
- 执行JavaScript代码,通常与主线程共享,但部分引擎支持多线程(如Web Worker)。
-
定时器线程(Timer Thread) :
- 管理
setTimeout和setInterval等定时器,触发回调。
- 管理
-
HTTP请求线程(Network Thread) :
- 处理网络请求,如XMLHttpRequest和Fetch API,通常与主线程分离。
-
Web Worker线程:
- 允许在后台运行JavaScript代码,独立于主线程,适合处理复杂计算。
-
Service Worker线程:
- 用于离线缓存和网络请求拦截,独立于主线程运行。
事件循环的工作流程
事件循环的核心是 任务队列(Task Queue) 和 微任务队列(Microtask Queue)
-
执行同步任务:
- 主线程执行当前调用栈中的同步任务(如 JavaScript 代码)。
-
检查微任务队列:
- 当调用栈为空时,主线程会检查微任务队列,依次执行所有微任务(如
Promise的回调)。
- 当调用栈为空时,主线程会检查微任务队列,依次执行所有微任务(如
-
渲染页面(如果需要) :
- 如果需要渲染页面(如样式计算、布局、绘制),主线程会执行渲染任务。
- 渲染任务通常由合成线程和光栅化线程协助完成。
-
从任务队列中取出一个宏任务执行:
- 主线程从任务队列中取出一个宏任务(如
setTimeout的回调)并执行。 - 执行完宏任务后,再次检查微任务队列并执行所有微任务。
- 主线程从任务队列中取出一个宏任务(如
-
重复上述过程:
- 主线程不断循环上述过程,直到所有任务队列为空。