看了深入理解现代浏览器这篇文章,写的非常好,记录一下。
开始划重点:
- 架构篇
chrome最新架构:
浏览器进程
:控制浏览器这个应用的chrome(主框架)部分,包括地址栏、书签、前进/后退按钮等,同时也会处理浏览器不可见的高权限任务,如发送网络请求、访问文件。渲染器进程
:负责在标签页中显示网站及处理事件。插件进程
:控制网站用到的所有插件。GPU进程
:在独立的进程中处理GPU任务。之所以放到独立的进程,是因为GPU要处理来自多个应用的请求,但要在同一个界面上绘制图形。
进程处理
- 正常情况,一个标签页就是一个
渲染器进程
。 - 为节省内存,Chrome会限制自己可以打开的进程数量。限制的条件取决于设备内存和CPU配置。达到限制条件后,Chrome会用一个进程处理同一个站点的多个标签页。
- 站点隔离(http://t.cn/RgNAwLC)。站点隔离是新近引入Chrome的一个里程碑式特性,即每个跨站点iframe都运行一个独立的`渲染器进程`。
- 正常情况,一个标签页就是一个
- 导航篇
标签页外面的一切都由
浏览器进程
处理,包括以下线程:UI线程
负责绘制浏览器的按钮和地址栏网络线程
负责处理网络请求并从互联网接收数据存储线程
负责访问文件和存储数据
输入url后
- 第一步:处理输入。
UI线程
会判断用户输入的是查询字符串还是URL - 第二步:开始导航。如果输入的是URL,
UI线程
会通知网络线程
发起网络调用,获取网站内容 - 第三步:读取响应。服务器返回的响应体到来之后,
网络线程
会检查接收到的前几个字节。
1
如果响应是HTML文件,那下一步就是把数据交给`渲染器进程`。但如果是一个zip文件或其他文件,那就意味着是一个下载请求,需要把数据传给`下载管理器`。
- 第四步:联系渲染器进程。
网络线程
确认浏览器可以导航到用户请求的网站,通知UI线程
数据已经准备好了。UI线程
会联系渲染器进程
渲染网页。 - 第五步:提交导航。数据和渲染器进程都有了,就可以通过IPC(进程间通信)从
浏览器进程
向渲染器进程
提交导航。渲染器进程
也会同时接收到不间断的HTML数据流。当浏览器进程
收到渲染器进程
的确认消息后,导航完成,文档加载阶段开始。 - 最后一步:初始加载完成。提交导航之后,
渲染器进程
将负责加载资源和渲染页面(具体细节后面介绍)。而在“完成”渲染后(在所有iframe中的onload事件触发且执行完成后),渲染器进程
会通过IPC给浏览器进程
发送一个消息。此时,UI线程
停止标签页上的旋转图标。
- 第一步:处理输入。
如果此时用户在地址又输入了其他URL呢?
1)浏览器进程还会重复上述步骤,导航到新站点。
2)在此之前,需要确认已渲染的网站是否关注beforeunload事件。
3)如果有beforeunload事件,必须渲染器进程
执行完毕,浏览器进程
才能导航到新站点。
4)导航到不同的网站时,会有一个新的独立渲染器进程
负责处理新导航,而老的渲染器进程
要负责处理unload之类的事件。
- 渲染篇
标签页中的一切都由
渲染器进程
负责处理主线程
负责运行大多数客户端JavaScript代码- 少量代码可能会由
工作线程
处理(如果用到了Web Worker或Service Worker) 合成器(compositor)线程
和栅格化(raster)线程
负责高效、平滑地渲染页面
加载子资源
- Chrome会在解析同时并发运行“预加载扫描器”,当发现HTML文档中有
<img>
或<link>
时,预加载扫描器
会将请求提交给浏览器进程
中的网络线程
。
- Chrome会在解析同时并发运行“预加载扫描器”,当发现HTML文档中有
- 交互篇
用户交互比如触摸事件发生时的过程:
浏览器进程
首先接收到该手势。但是,浏览器进程仅仅知道手势发生在哪里,浏览器进程
会把事件类型(如touchstart)及其坐标发送给渲染器进程
处理这个事件,即根据事件目标来运行注册的监听程序。因为标签页中的内容是渲染器进程
处理。
事件处理
- 输入事件是由
渲染器进程
中的合成器线程
处理的。 - 如果页面上没有注册事件监听程序,那合成器线程可以完全独立于主线程生成新的合成器帧。
- 如果页面上注册了事件监听程序呢?此时合成器线程怎么知道是否有事件要处理?
- 输入事件是由
为什么事件监听要加上
passive:true
?
1 | document.body.addEventListener('touchstart', evt => { |
- 自己看文章吧
- 大概原理是,如果把事件监听都挂载到document.body, 那么在处理每一次事件的时候,都需要
渲染器进程
的合成器线程
先进行js事件的判断,再合成新帧。而加了这个之后,就可以同步进行了。