Electron架构深入探究

目录
  • Electron是什么
  • Electron架构
  • 小结

Electron是什么

引用来自官网的解释:

Electron 是一个使用 JavaScript、 HTML 和 CSS 构建桌面应用程序的框架。通过将 Chromium 和 Node.js 嵌入到它的二进制文件中,Electron 允许你维护一个 JavaScript 代码库,并创建可以在 Windows、 macOS 和 Linux 上运行的跨平台应用程序ーー不需要本地开发经验。

如果我们追溯历史,可以发现Electron的前身是Atom Shell,最开始的设计目标就是为Atom编辑器而生,实际上Electron的作者之前也是node-webkit的核心贡献者,而node-webkit正是NW.js的前身。在作者离开英特尔公司(当初大力支持node-webkit)后,就加入了Github项目组,孵化了Atom Shell这个项目,再到后来(2014年)正式更名为Electron,发展至今。

Electron和众多类似的产品目标非常简单,他们将chromium(这里不同的框架选择不同,比如Tauri选择了原生的WebView,而WebView2选择了Edge内核)和Node.js(这里不同框架采取策略也不同,比如Webview2不提供默认的运行时,而Tauri选择了Rust等等)利用C++等原生语言集成起来,提供了一整套基于Web的运行环境,并提供了与底层OS交互的便捷API,目的就是为了让大家使用Web的技术栈去开发客户端原生应用,从而实现不同操作系统之间的跨平台开发。

说起桌面端GUI跨平台开发不得不提到Qt,这个使用C++来统一各个平台开发的框架才能被称为桌面跨端开发的鼻祖。在之前每个操作系统都是各自为战,经历过windows时代的MFCWPF的开发模式,在Mac上则是OCSwift作为底层语言,在经历了互联网时代变迁后,跨端框架越来越被大家所喜爱,广泛运用于互联网产品中。

若论起性能,肯定是越接近底层的语言开发出来的软件性能越高。如果要追溯历史,最底层的编程方式大概是最早的纸带打孔编码的时代,那时的人们是真正的编程大师,在用机器码编程,写二进制程序是非常复杂的,只通过0和1两个数字完成如此复杂的逻辑代码,基本上是需要巨大的精力和时间的,所以这个时代的程序只能做非常简单的事情。到后来汇编语言的产生才能让一些操作逐渐复杂一些,但依旧无法完成更复杂的架构设计。直到高级语言的出现,才让软件世界逐渐丰富多彩了起来,在计算机上产生了令人震惊的软件和操作系统,进入个人电脑时代,改变了世界。

在高级语言中,C语言应该是最接近底层的开发语言了,因此常用的操作系统内核基本都是用C语言和汇编写成,这是因为内核需要极高的性能以及对底层硬件驱动的精确控制。后来经过工程师在工程方面的不断探索,有了面向对象,编程范式,有更高层利于维护的语言出现。C++可以说是介于C和更高级语言之间的一个产物,它完全兼容C的语法,又添加了面向对象、STL模板等能力,让他在能拥有不俗的性能的同时,还拥有一定的大型工程化的能力,我们所了解到的大多数最复杂的软件,比如浏览器Chrome、Office、编译器、游戏等等,尤其是最复杂的浏览器软件,浏览器内核的复杂程度远超我们想象,也正是有chromium这样的开源贡献,造就了今天互联网时代的技术繁荣,基于V8LibUV构建的Node.js让前端迅速发展到一个不可思议的地步,本文所讲的Electron也同样依赖于这样的技术。

回到性能的讨论,毫无疑问在引入了chromiumNode.js作为运行时的Electron性能是不如基于C++Qt,同样Qt的性能也不及直接使用原生语言来开发的程序,多一层抽象的封装必然会折损一部分性能。那是不是说用性能越好的语言来开发就是最优的呢?答案显然不是,不然现在我们应该直接用机器码来开发。实际上,软件语言和框架的发展,离不开硬件的高速发展,硬件遵循着摩尔定律发展至今,硬件的计算能力、存储能力都有着飞跃式的进步,这才能够让软件脱离底层的束缚,越来越专注于工程的可维护性和易用性,释放掉一些不必要的生产力,让软件的世界发展到今天这种繁荣的地步。

毫无疑问,Electron是处于最上层的抽象层级当中,通过简单高效的Web技术来实现复杂的桌面软件开发。从语言发展的视角来看,C和C++可以对内存进行精细地控制访问,而底层的汇编则更可以操纵寄存器,存储越靠近CPU运行速度就会越快。但是它带来的代价是昂贵的开发成本和安全问题,还记得在windows时代有着各种蠕虫木马病毒,很大一部分都是程序本身的缓冲区溢出、访问越界等等问题,这类底层的语言对开发人员的要求较高,需要能够掌握操作系统的内部机制,在大型工程的情况下,bug是难免的,而底层语言造成的bug往往影响面更大。因此后来Java等语言去除了指针的设计,弱化了对内存的控制程度,增强了工程化的能力,以更好地应对复杂的软件环境。再到后来pythonjavascript等脚本语言的流行,更简化了开发人员编写代码的成本,涌现多种编程范式和繁荣的生态。而新兴的现代化编程语言如golangrust等则是性能与易用之间的权衡,从这个发展趋势来看,大家一直在探寻着一个平衡点。

从另一个角度来看,软件的研发成本和产品、商业也息息相关,行业巨头Google、微软、IBM等大型软件公司,都曾面临过无法按时交付的问题。人月神话中也深刻地揭示了软件开发的工期不是靠纯堆人力就能将问题解决的,一旦有这类风险产生,无论是对企业还是用户都会造成比较大的伤害。而越是底层的语言,所需要软件开发人员的专业素质越高,维护成本也就越高,因此在互联网高速发展的时代,系统开发相关的人才不断减少,更多涌现出大量的应用开发人员,进入Web高速发展的阶段。这是由于互联网业务的高速发展、软硬件技术的不断迭代更新,形成的一种趋势。因此ElectronReact NativeFlutteruniAppTaro这类跨端解决方案越来越受大家欢迎也是必然的结果。

Electron架构

ElectronJS 进程模型图解

Electron的架构设计很大程度上是受到Chromium的启发。ChromiumGoogle开源的浏览器内核代码,ChromeEdgeOpera等等浏览器都是基于Chromium来实现的。Chromium堪称是全世界最复杂的软件应用,整体代码库已经庞大到了近40G,我们简单举个例子说明下其复杂程度:

  • net模块,实现了主机解析,cookies,网络改变探测,SSL,资源缓存,ftp,HTTP, OCSP实现,代理 (SOCKS和HTTP) 配置,解析,脚本获取(包括各种不同系统下实现),QUIC,socket池,SPDY,WebSockets等等,每套协议都是十分复杂的。
  • v8模块,包括字节码解析器,JIT 编译器,多代GC,inspector (调试支持),内存和 CPU 的 profiler(性能统计),WebAssembly 支持,两种 post-mortem diagnostics 的支持,启动快照,代码缓存、代码热点分析等等。
  • Skia模块,用点画出各种图。然而里面包括十几种矢量的绘制,文字绘制、GPU加速、矢量的指令录制以及回放(还要能支持线程安全)、各种图像格式的编解码、GPU渲染优化等等。
  • Blink内核,这个更复杂,HTMLCSS规范就得近万页了,要将它们完全实现是一个巨大的工作量,再加上实现Layout的成本,涉及到非常庞大的计算,还要考虑极致的性能,保证浏览器的渲染能够流畅快速。
  • 还有音视频相关、沙箱、插件、UI等等,就不赘述了,总之称之为巨型软件应用也不为过,

正是由于这一庞大复杂架构的开源,经过数年的不断打磨完善,让Web技术能够快速发展,百花齐放。

我们知道,在浏览器内部有很多的处理模块,这些模块的代码可以采用进程或者线程的方式来进行组织调度:

browser architecture

在浏览器实现方面是没有标准规范的,这取决于不同浏览器内部的实现细节。在最早期,浏览器渲染都是在同一个进程里面完成的,后来Chrome采用了多进程架构,演变成了这种模式:

browser architecture

其中:

  • 浏览器主进程,实现浏览器的主要UI、负责和文件、网络等等操作系统底层接口对接通信。
  • 渲染进程,每一个tab独立开一个渲染进程,核心进行web代码解析和渲染工作。
  • 插件进程,负责浏览器插件的控制。
  • GPU进程,独立的进程负责处理GPU图像的渲染绘制。

这样设计架构的好处主要有两个:

  • 保证每个tab独立进程,这样在某一个页面crash的时候,仅仅影响当前的Tab,而不至于让整个浏览器崩溃。这提升了软件的健壮性和用户体验。
  • 有利于实现沙箱隔离的安全机制,基于进程可以很方便地控制不同页面之间的安全访问策略,确保每个renderer进程在自己单独的沙箱环境内安全地运行。

不过这类架构也带来一个额外的成本,那就是更多的内存消耗,因为每一个进程需要开辟独立的内存空间,不同进程之间的内存很难做到共享。因此这个策略也是个权衡的策略考虑,Chrome基于用户当前的CPU和内存的情况,对进程的数量进行了动态的限制,以确保达到一个最佳的效果。

Electron本身参考了这个架构的实现,将各个GUI窗口通过renderer进程实现,交由chromium来加载渲染,主进程集成Node.js,负责与系统API交互,处理核心事务。

我们可以从Electron源码结构上很清晰地看到这点:

Electron
├── build/ - 构建相关
├── buildflags/ - feature flag
├── chromium_src/ - chromium的一份拷贝(源码仅包含build文件)
├── default_app/ - 默认启动时的app程序
├── docs/ -文档
├── lib/ - 使用JS/TS编写的模块
|   ├── browser/ - 主进程初始化相关
|   |   ├── api/ - 主进程暴露的API,通过_linkedBinding调用C++模块
|   ├── common/ - 主进程和渲染进程共用代码
|   |   └── api/ - 主进程和渲染进程共同暴露的API
|   ├── renderer/ - 渲染进程初始化相关
|   |   ├── api/ - 渲染进程API
|   |   └── web-view/ - webview相关逻辑
├── patches/ - 关于依赖的一些patch,主要是chromium、node、v8的
├── shell/ - C++编写的模块
|   ├── app/ - 入口
|   ├── browser/ - 主进程相关
|   |   ├── ui/ - 系统UI组件的一些实现
|   |   ├── api/ - 主进程API实现
|   |   ├── net/ - 网络相关实现
|   |   ├── mac/ - Mac系统下的一些实现(OC实现)
|   ├── renderer/ - 渲染进程相关
|   |   └── api/ - 渲染进程API实现
|   └── common/ - 主进程渲染进程通用实现
|       └── api/ - 主进程渲染进程通用API实现
└── BUILD.gn - 构建入口

Electron在源码上与Node.js实现类似,lib目录使用js实现,通过_linkedBinding来调用C++的模块,在一开始会被编译进内存中,通过C++程序装在启动。

C++启动入口在shell/app/electron_library_main.mm:

int ElectronMain(int argc, char* argv[]) {
  electron::ElectronMainDelegate delegate;
  content::ContentMainParams params(&delegate);
  params.argc = argc;
  params.argv = const_cast<const char**>(argv);
  electron::ElectronCommandLine::Init(argc, argv);
  return content::ContentMain(std::move(params));
}

这里依赖的content实际上是chromiumcontent模块,chromium将浏览器主进程部分和渲染进程进行了抽象,主进程部分的逻辑在blink模块实现,而渲染进程相关的实现则封装在content模块。

所以这里调用content就可以使用chromiumrenderer进程来进行启动渲染了。

关于C++部分的核心实现会在后续文章中进一步探讨。

小结

Electron本质上就是集成Node.jsChromium提供了基于Web技术栈开发客户端软件的能力,通过Web技术栈的快速迭代和Chrome本身的向前兼容迭代能力,可以做到跨平台的快速迭代开发。

在软件发展的进程中,我们始终在平衡软硬件之间的性能关系,性能与成本的平衡,软件维护和生态的持续发展,基于互联网的发展,Web技术的发展,促成了Electron这样的跨端技术被广泛应用。

Electron在实现架构上参考了Chromium的核心设计思想,通过主进程进行核心的调度启动,不同的GUI窗口独立渲染进程,并提供沙箱安全机制,做到进程间的隔离,进程与进程之间实现了IPC通信机制,对主进程提供Node.js运行时,封装上层API,通过C++提供具体系统组件、系统方法能力的实现。

以上就是Electron架构深入探究的详细内容,更多关于Electron架构的资料请关注我们其它相关文章!

(0)

相关推荐

  • Web Worker线程解决方案electron踩坑记录

    目录 初始化项目 编写入口文件和 electron 插件 websocket websocket 服务 连接 websocket 服务 发送心跳 取消心跳 重新连接 其它优化 Worker 初始化项目 electron 开发时会遇到一对多的情况,在进行 websocket 通信时,如果接收到服务端多个指令时,而这个指令刚好需要占用线程,这个时候整个界面就会失去响应,那么我们就可以使用线程来解决这个问题. npm create vite@latest electron-worker 执行完后修改

  • AntDesignPro使用electron构建桌面应用示例详解

    目录 注意事项声明 主要分为两个部分 开发环境使用 打包应用配置 package.json配置打包后的路径方式 使用 electron-builder 打包 exe 文件或者安装包,压缩包 安装 package.json添加命令 (打包windows) 添加打包配置 执行打包命令 使用 electron-packager 打包成 exe 文件 执行命令 提示 注意事项声明 所有 node 包必须使用 npm 安装不可使用 cnpm, 使用 cnpm 安装的 node 包会导致打包时间无限可能 具

  • 详解Electron中如何使用SQLite存储笔记

    目录 前言 数据库的选择 安装 创建表 Service Controller 业务 总结 前言 上一篇,我们使用 remirror 实现了一个简单的 markdown 编辑器.接下来,我们要学习如何去存储这些笔记. 当然了,你也可以选择不使用数据库,不过若是你以后需要将该应用上架到 mac Apple Store ,就需要考虑这个了.因为上架 mac 应用需要启用 sandbox,当你第一次访问笔记中的媒体文件时,都要打开选择文件的弹窗,通过让用户主动选择来授权访问沙箱外的媒体文件.不过,如果你

  • vite + electron-builder 打包配置详解

    目录 创一个vite项目 安装打包工具 配置桌面环境 创建 主进程 main.js 添加electron 运行命令 打包项目,生成dist 解决资源无法加载 开发环境:热更新 两个工具 concurrently wait-on 打包exe 解决index.html找不到的问题 创一个vite项目 npm init vite 安装打包工具 npm i -D electron // 20.1.0 npm i -D electron-builder // 23.3.3 electron是开发时运行环境

  • Electron架构深入探究

    目录 Electron是什么 Electron架构 小结 Electron是什么 引用来自官网的解释: Electron 是一个使用 JavaScript. HTML 和 CSS 构建桌面应用程序的框架.通过将 Chromium 和 Node.js 嵌入到它的二进制文件中,Electron 允许你维护一个 JavaScript 代码库,并创建可以在 Windows. macOS 和 Linux 上运行的跨平台应用程序ーー不需要本地开发经验. 如果我们追溯历史,可以发现Electron的前身是At

  • vscode刷acm、leetcode的题目

    目录 简介 编译器 Windows 使用 Code Runner 插件运行代码 使用 C/C++ 插件编译并调试 安装插件 配置编译 配置 GDB/LLDB 调试器 开始调试代码 简介 Visual Studio Code(以下简称 VS Code) 是一个由微软开发,同时支持 Windows.Linux 和 macOS 等操作系统且开放源代码的代码编辑器.它是用 TypeScript 编写的,并且采用 Electron 架构.它带有对 JavaScript.TypeScript 和 Node.

  • Android Jetpack架构中ViewModel接口暴露的不合理探究

    目录 暴露 Mutable 状态 暴露 Suspend 方法 在 Jetpack 架构规范中, ViewModel 与 View 之间应该遵循单向数据流的通信方式,Events 永远从 View 流向 VM ,而 State 从 VM 流向 View. 如果 ViewModel 对 View 暴露了不适当的接口类型,则会破坏单向数据流的形成.不适当的接口类型常见于以下两点: 暴露 Mutable 状态 暴露 Suspend 方法 暴露 Mutable 状态 ViewModel 对外暴露的数据状态

  • BackBone及其实例探究_动力节点Java学院整理

    MVC简介 基本介绍 MVC即模型(Model),视图(View)和控制(Controller),旨在实现Web系统的职能分工,具体来说就是使业务逻辑和数据显示分离. 在MVC中,视图(View)为用户提供交互,模型(Model)负责处理数据和业务逻辑,控制器(Controller)则是View与Model之间沟通的桥梁. MVC一个很重要的标志就是,视图(View)与模型(Model)没有直接的交互,而是通过控制器(Controller)来沟通.具体地:用户通过View进行输入,Control

  • 详解Angular CLI + Electron 开发环境搭建

    本文介绍了Angular CLI + Electron 开发环境搭建,分享给大家 用 @angular/cli 配合 Electron 构建桌面软件开发环境,可以在 Electron 中使用 Angular 的各种特性,使开发桌面软件像开发网站一样简单.快捷,而且可以模块化,紧跟最新技术趋势. 安装 Angular CLI 和 Electron 首先使用 npm 安装 Angular Cli: $ npm i -g @angular/cli 然后安装 Electron $ npm i -g el

  • 深入探究node之Transform

    本文详细的介绍了node Transform ,分享给大家,希望此文章对各位有所帮助. Transform流特性 在开发中直接接触Transform流的情况不是很多,往往是使用相对成熟的模块或者封装的API来完成流的处理,最为特殊的莫过于through2模块和gulp流操作.那么,Transform流到底有什么特点呢? 从名称上说,Transform意为处理,类似于生产流水线上的每一道工序,每道工序针对到来的产品作相应的处理:从结构上看,Transform是一个双工流,通俗的解释它既可以作为可读

  • Windows Server 2003探究

    Windows Server 2003探究 解剖WinServ03(一) 让我们一道进入Microsoft的服务器重拳WinServ03中来看看,到底它带给我们什么. 在上次的手记(欢迎莅临.Net世界)中我们了解到了Window Server 2003(下简称WinServ03)的大致的发布情况以及Windows Server 2003 Family家族中的各位成员.但是并未对WinServ03的具体情况做太多的介绍.    今天就让我们一道进入Microsoft的服务器重拳WinServ03

  • 前端Electron新手入门教程详解

    Electron 是什么 定义 Electron是一个能让你使用传统前端技术(Nodejs, Javascript, HTML, CSS)开发一个跨平台桌面应用的框架.这里所说的桌面应用指的是在Windows.OSX及Linux系统上运行的程序. 历史 2013年的时候,Atom编辑器问世,作为实现它的底层框架Electron也逐渐被熟知,到2014年时被开源,那时它还是叫Atom Shell. 接下来的几年,Electron在不断的更新迭代,几乎每年都有一个重大的里程碑 2013年4月11日,

  • SpringBoot集成Redis并实现主从架构的实践

    目录 一.Windows环境下安装Redis 设置键值对 根据key获取value 二.SpringBoot连接Redis (1)使用Jedis类直接连接Redis服务器 (2)通过配置文件进行连接 三.使用连接池操作Redis 今天这篇文章来和大家分享一下在springboot中如何集成redis,并实现主从架构,进行数据的简单存储. 我的Redis是部署在Windows系统下面的,所以在这里附上Redis在Windows环境下的安装地址和安装说明. 一.Windows环境下安装Redis 首

  • JavaScript架构前端不能没有监控系统原因

    目录 监控系统 前端监控具体能解决什么问题? 异常报错问题 性能检测问题 运营反馈工具 为什么要选择自研? 自研前端监控的技术栈 监控系统 提到监控系统,大部分同学首先想到的是后端监控.很明显,比如检测服务器性能,数据库性能,API 的访问流量,以及各种服务的运行情况等等,都与后端息息相关.而前端更多承担的是 UI 展现的角色,主要关注页面怎么排版设计,好像没什么需要监测的地方,因此一直以来都没有涉及到监控的概念. 于是呢大家就一致认为:只要后端稳定可控,应用就是稳定可控的,可实际情况真的是这样

随机推荐