文章目录
- Chromium 架构
- Electron 架构
Chromium 架构
主体架构:主进程 Browser,打开一个页面就会启动一个 Render 渲染进程,进程间通信就是 IPC 机制(Inter-Process Communication)。
主进程的 RenderProcessHost 和 Render 进程的 RenderProcess 就是用来专门处理 IPC 事件的。
具体来看渲染进程,我们最熟悉的网页就是在 RenderView 中由 WebKit 排版后展示出来的。ResourceDispatcher 是用来处理资源请求的,当页面要请求某些资源的时候,会通过资源调度器 ResourceDispatcher 创建一个请求 id,然后转发到 IPC,在 Browser 进程里处理,然后返回。
总结:
- chromium 是多进程架构,1 个 Browser 进程多个 Render 进程
- 进程间需要 IPC 通信
- 我们关注的 web 只是很小的一部分
Electron 架构
Electron 架构和 Chromium 架构类似也是一个主进程,多个渲染进程。但不同的是:
- Electron 在各个进程里暴露了 Native API
- 引入了 node.js,可以用 node 去管理窗口,还可以在页面中使用 node 的库。
页面上能使用 node,要实现这点其实很不容易。
因为主进程同一时间只能执行一个事件循环。node.js 的事件循环基于 Libuv
,而 Chromium 的事件循环基于 message bump
,所以问题来了,主进程在同一时间是执行 node.js 还是 Chromium 呢?
这就是 Electron 解决的重点问题。
解决这个问题,思路就是两者的事件循环要整合成一个,这样主进程才不会冲突。
具体有两种思路:
- Chromium 融合进 node:用 Libuv 实现一遍 message bump。
- NW 就是这么干的。
- node 融合进 Chromium。
electron 当初也像 NW 一样,但是发现渲染进程中实现很简单,但是主进程中确很复杂,因为各个系统的 GUI 实现都不一样,比如 Mac 是 NSRunLoop,Linux 是 glib。工程量浩大,但最致命的是各种边界情况处理不好。
后来作者又重新尝试了一个思路,用一个小间隔定时器去轮询 GUI 事件,然后发现 GUI 响应很慢,CPU 占比也高。
直到 libuv 引入了 backend_fd 的概念,它相当于 Libuv 轮询事件的文件描述符。那我们可以轮询这个 backend_fd,从而知道 Libuv 中循环的事件。这就给 Chromium 融合 Node 创造了机会。
所以 Electron 的最终做法就是将 Node 的事件循环整合进了 Chromium。
Electron 起了一个安全的线程去轮询 backend_fd。当 Node.js 产生了一个新的事件后,轮询就会发现这个新事件,然后通过 PostTask 转发到 Chromium 的事件循环中。这样 Electron 就完成了事件融合。
- Electron Internals: Message Loop Integration | Electron