进程与线程
面试速答(30 秒版 TL;DR)
- 进程(Process) 是资源分配的基本单位,线程(Thread) 是 CPU 调度的基本单位。
- 浏览器之所以快且稳定,不是靠“单线程”,而是靠多进程架构 + 渲染进程内多线程协作。
- 常见进程包括:浏览器主进程、渲染进程、GPU 进程、网络进程、插件进程。
- JS 常被说成“单线程”,更准确地说是:页面里的 JS 主线程通常一次只执行一个任务,但整个浏览器不是单线程程序。
心智模型:浏览器像一个小型操作系统
浏览器不是单个程序顺序执行完所有事,而是把不同职责拆到不同进程、不同线程里:
- 有的负责界面和标签管理
- 有的负责页面渲染
- 有的负责网络请求
- 有的负责 GPU 合成
这样做的核心价值有三个:
- 稳定性:一个页面崩了,不至于把整个浏览器拖死。
- 安全性:不同站点隔离,降低互相影响。
- 性能:不同任务可以并行推进。
浏览器的典型多进程架构
先看最上层分工:谁在总控,谁在负责页面、网络和 GPU。
1. 浏览器主进程
主要负责:
- 标签页管理
- 地址栏、前进后退、书签等浏览器 UI
- 协调各个子进程
- 用户输入事件分发的上层控制
2. 渲染进程
每个标签页或站点实例通常会分配渲染进程。它负责:
- HTML/CSS/JS 执行
- 页面布局与绘制
- DOM、CSSOM 构建
这也是前端最常接触到的运行环境。
3. 网络进程
负责:
- 发起和管理网络请求
- 缓存、Cookie、连接复用等网络层能力
4. GPU 进程
负责:
- 图层合成
- GPU 加速绘制相关任务
渲染进程里又有哪些线程
GUI 渲染线程
负责:
- 解析布局
- 绘制页面
- 参与合成流程
JS 引擎线程
负责:
- 执行 JS 代码
- 处理宏任务、微任务调度结果
为什么 GUI 线程和 JS 线程不能同时随便跑
因为 JS 可以改 DOM:
document.querySelector('#app').innerHTML = 'new content'
如果 GUI 线程正在根据旧 DOM 渲染,而 JS 线程同时把 DOM 改掉,就会有状态一致性问题。所以通常会通过调度机制避免两者无序并发。
为什么说 JavaScript 是单线程
更准确的表述应该是:
在一个渲染上下文里,JS 主线程通常按事件循环一次处理一个任务。
它不代表:
- 浏览器只有一条线程
- JS 完全不能并发
因为浏览器可以通过这些方式实现“异步协作”:
- 定时器线程到时间后把回调放入任务队列
- 网络线程请求完成后通知事件循环
Web Worker在额外线程执行脚本
多进程架构为什么重要
1. 页面崩溃隔离
一个标签页出现脚本崩溃或内存问题,通常只影响对应渲染进程。
2. 站点隔离与安全
现代浏览器会做更严格的站点隔离,降低不同站点直接互相读写内存的风险。
3. 并发能力更好
网络、渲染、合成都可以拆到不同线程或进程协作完成。
典型题 & 标准答法
Q1:进程和线程的区别是什么?
答:进程是资源分配的基本单位,线程是 CPU 调度的基本单位。一个进程可以包含多个线程,线程共享进程资源但执行路径独立。浏览器采用多进程架构,是为了稳定性、安全性和并发能力。
Q2:浏览器是单进程还是多进程?
答:现代浏览器是多进程架构。至少会有浏览器主进程、渲染进程、网络进程、GPU 进程等。一个页面通常运行在渲染进程里,而不是整个浏览器只有一条执行线。
Q3:为什么说 JS 是单线程?
答:通常是指在一个页面上下文里,JS 主线程一次只执行一个任务,避免和 DOM 渲染并发修改带来一致性问题。但这不代表浏览器只有一条线程,也不代表前端不能借助异步线程或 Worker 实现并发协作。
常见追问
- 一个标签页一定对应一个渲染进程吗?
Web Worker和主线程是什么关系?- 事件循环和多线程协作是怎么配合的?
易错点
- 不要把“JS 单线程”说成“浏览器单线程”。
- 不要把“线程安全问题”简单说成“所以 JS 不能异步”。异步很多,只是执行回调最终仍需回到事件循环调度。
- 不要绝对化“一页一进程”。现代浏览器会结合站点隔离、资源和策略动态分配。
速记要点
- 浏览器整体是多进程,渲染进程内部是多线程协作。
- JS 主线程通常串行执行任务,但网络、定时器、合成并不都在这条线程上。
- 多进程的目标:稳定性、安全性、并发能力。