Electron架构揭秘
「观感度:」
「口味:麻辣爆肚」
「烹饪时间:10min」
本文已收录在前端食堂同名仓库Github github.com/Geekhyt,欢迎光临食堂,如果觉得酒菜还算可口,赏个 Star 对食堂老板来说是莫大的鼓励。
彩蛋
昨晚搬砖回家看到 Peter 发了条朋友圈,腾讯云游戏平台 START 公测发布,他在用 MAC 打 LOL。我紧随其后体验了一波,毕竟 LOL 是我们这代人的青春,工作后很少有时间玩,用上 MAC 后,之前的游戏本也放在箱底很久了。
选个 EZ 浪一浪~(天赋都没来得及换)
20 分钟轻松拿下首胜(毕竟 s2 老玩家了,匹配局常规操作),综合体验还是很不错的,家用网速下基本感觉不到延迟,除了窗口模式下调整视角时鼠标有点难受之外。(想要体验的同学记得先把触发角关了)
云游戏平台这种“云”模式彻底解放了“跨平台”的想象力,随着 5G 的到来,它有没有可能是未来解决跨平台的最佳方案呢?对我们前端工程师来说,等待我们的又会是什么新的挑战呢?欢迎同学们留言一起探讨~
书归正传,最近手头在做 Electron 的项目,Electron 为了实现跨平台做了很多努力。(刚好可以与云游戏平台这种模式形成对比。)下面我们来一起看一看。
浏览器架构演进
我们先从浏览器架构演进开始说起,日益复杂的业务需求不断 push 着浏览器架构不断的演进和迭代。
拿我们最喜欢的 Chrome
举例,从 2007 年以前的单进程架构到现在的多进程架构,浏览器因为架构的调整,
变得更加稳定、更加流畅、更加安全。目前你能看到的最新的 Chrome
浏览器应该包括如下进程:
-
1 个浏览器(Browser)主进程
-
1 个 GPU 进程
-
1 个网络(NetWork)进程
-
多个渲染进程 (运行在沙箱模式下)
-
多个插件进程
不过,软件工程没有银弹。浏览器的架构体系也随着调整变得更加复杂, 也会有更高的资源占用。
如何寻求一种在资源占用和复杂架构体系之间的平衡便成为了一个难题。
「小孩子才做选择,鱼和熊掌我都要!」
Chrome 团队在 2016 年使用“面向服务的架构”(Services Oriented Architecture,简称 SOA)的思想设计了新的 Chrome 架构。
Chrome
团队将模块重构成独立的服务 ( Service
),服务运行在独立的进程中,想要访问的话必须使用定义好的接口,通过 IPC
来进行通信。这样的架构无疑更加内聚、松耦合、易于维护和扩展。
Chromium 架构
Chromium 是 Chrome
的开源版,也是一个浏览器。
- 主进程的
RenderProcessHost
和 渲染进程的RenderProcess
专门处理IPC
事件。 - 渲染进程的
RenderView
: 我们的页面就是在这里基于Webkit
排版展示出来的。 -
ResourceDispatcher
处理资源请求,当页面需要请求资源时,通过ResourceDispatcher
,创建一个请求ID
转发到IPC
,在Browser
进程中处理然后返回。
Electron 架构
- 在各个进程中暴露了
Native API (Main Native API、Renderer Native API)
- 引入
Node.js
这样,在 Electron
中就可以使用 Chromium
和 Node.js
做好玩的事情了!
不过在此之前,还有一个难点需要解决:如何将 Node.js
和 Chromiums
整合?
Node.js
事件循环基于 libuv,但 Chromium
基于 message_pump。
解决这个问题的的主要思路有两种:
- 1.将
Chromium
集成到Node.js
:用libuv
实现message_pump
。 - 2.将
Node.js
集成到Chromium
。
第一种方案, NW.js 就是这么做的。 Electron
前期也是这样尝试的,结果发现在渲染进程里实现比较容易,但是在主进程里却很麻烦,因为各个系统的 GUI
实现都不同, Mac
是 NSRunLoop
, Linux
是 glib
,不仅工程量十分浩大,而且一些边界情况处理起来也十分棘手。
后来作者另辟蹊径,再次进行尝试,用一个小间隔的定时器轮询 GUI
事件,发现 GUI
响应的非常慢, CPU
也爆表。
直到后来 libuv
引入了 backend_fd
的概念,相当于 libuv
轮询事件的文件描述符,这样就可以通过轮询 backend_fd
来得到 libuv
的一个新事件了。也就是第二种思路,将 Node.js
集成到 Chromium
。
如果你想了解更多,也可以去看看下面作者的这个知乎回答~
小结
将 Node.js
集成到 Chromium
中的原理:
Electron
起了一个新的安全线程去轮询 backend_fd
,当 Node.js
有一个新的事件后,通过 PostTask
转发到 Chromium
的事件循环中,这样就实现了 Electron
的事件融合。
参考
- 《浏览器工作原理与实践》 李兵
- 《Electron开发实战》 邓耀龙
❤️爱心三连击
1.如果你觉得食堂酒菜还合胃口,就点个赞支持下吧,你的 「赞」是我最大的动力。
2.关注公众号前端食堂, 「吃好每一顿饭!」
3.点赞、评论、转发 === 催更!