Electron–用Web的方式写跨平台桌面应用
在前两年的时候,我已经听说过Electron这个框架。当时对Nodejs、ES6这些新的内容和特性还不很了解,加上Electron只有英文的文档,因此没有怎么了解它。前段时间了解了Nodejs后,借着一个项目的契机,我又把Electron提上了学习日程。与两年前不同,现在的Electron的大部分文档已经具有中文译文,网上也可以搜到不少相关的文档作为参考。
这篇文章主要是介绍Electron的基础知识,不会涉及过多的代码细节。如果我们已经掌握了前端基础知识(HTML、CSS、JavaScript、Nodejs),在了解Electron的基本工作原理后,编写代码其实并不困难。
简单介绍
放在开头,我们要记住Electron的官方文档页面链接。官方文档是开发必不可少的参考资料,而且它会保持最新,要常去看一看。
Electron官网
Electron | 使用 JavaScript, HTML 和 CSS 构建跨平台的桌面应用。
Electron官方文档与API手册
文档 | Electron
API | Electron
让我们看看官方是怎样介绍Electron的
Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库。 Electron通过将Chromium和Node.js合并到同一个运行时环境中,并将其打包为Mac,Windows和Linux系统下的应用来实现这一目的。
Electron官网如是说
Electron于2013年作为构建Github上可编程的文本编辑器Atom的框架而被开发出来。这两个项目在2014春季开源。
我们可以大致归纳Electron的几个特点:
- 使用Web前端的技术构建桌面应用
- 核心是Chromium和Nodejs
- 跨Windows、Mac、Linux三种系统
对于大部分前端开发者来说,它提供了一种构建桌面应用的新方式。
使用Electron的优势
对于前端开发者来说,开发的应用不仅局限在Web页面,还可以制作桌面应用(本质上还是在浏览器中运行,只是这个浏览器提供了一些开发者可以使用的API)。前端的职业出路似乎更宽了一些。
传统桌面应用开发中,Windows平台对应的主流开发程序是C#,而Mac平台下的主流开发程序是Objective-C。跨平台桌面应用开发还有一个Qt框架,不过Qt框架内部细节依然比较复杂,学习成本较高。对比前面三种开发模式,Electron比较方便的做到了跨平台版本的开发。同一套程序,执行不同的打包命令就可以得到不同平台上的可执行文件。JavaScript和Nodejs的学习成本要低很多。另外,Electron还提供了应用签名、自动更新、发布到应用商店的支持,简化了发布的过程。
Electron隐藏了很多系统底层的细节,让我们更加专注业务逻辑的设计与实现。比如Windows下使用C#开发,我们需要了解操作系统的底层接口以及系统事件,而Electron开发下,我们并不需要知道这些。
Electron可以使用自身提供的API,还可以使用大多数Nodejs的库,也可以使用大多数纯JavaScript的库,包括jquery。这样我们可以充分利用别人造好的轮子来快速搭建我们的应用。在C#、Objective-C上,我们可能需要在造轮子上花费较多的时间。
Electron构建的应用,展示出来的就是Web前端页面,因此大部分前端框架都可以应用在Electron应用的构建中,比如Vue、React。同时,得益于CSS的蓬勃发展,我们可以很方便地实现很多好看的样式。而这些样式在传统的桌面应用中不那么容易实现。举个简单的例子,输入框可以通过border-radius属性设置成圆角。这个在C#中就不那么容易实现了(你需要创建一个方形遮罩层,然后根据4边裁剪圆角,最后将这个遮罩层覆盖在输入框上)。
相比于浏览器中的Web页面,Electron桌面应用可以做到离线使用。同时,它可以跳出浏览器功能的限制,方便地进行诸如读写文件这样的操作。还可以与系统的配置、环境变量、消息队列结合,有一种突破次元的感觉。
Electron的不足
虽然前面吹了不少Electron的优点,但是它依然不可能做到完美。下面列举一些Electron的不足之处。
由于Electron在我们和操作系统中间增加了一层封装,这也就意味着我们无法直接调用系统底层的接口或监听系统事件。对于一个功能,Electron如果没有提供相关API,我们便无法使用这个功能。
由于Electron是基于Chromium的,一个页面只有一个渲染进程。这对于某些需要多线程进行大量计算的程序是个短板。
Electron打包产生的项目大小相当大,同样的功能在Windows上使用C#开发,得到的项目大小也就是10分之一。
Electron在打包时将运行库进行了封装,因此不利于在运行时动态地加载/卸载功能。Windows系统上,我们可以利用dll文件动态地加载需要的功能。
Electron的进程模型
进程模型对于Electron应用开发非常重要,请务必阅读并理解。
一个Electron应用具有两类完全不同的进程。一种是main.js运行的进程,被称为主进程(Main process)。另一种是页面运行的进程,被称为渲染进程(Render process)。我们可以这样来理解:主进程就是Chromium的进程,我们的页面都运行在Chromium上,每个页面都是一个独立的渲染进程。换句话说,渲染进程与浏览器沙盒模型中的页面进程是一样的,主进程就是浏览器。
主进程
主进程是main.js运行的进程,本质上就是一个Chromium。主进程本身具有与操作系统交互的能力,因此它主要是完成系统相关操作。比如打开文件选择窗口,在消息栏显示消息等等。所有的Web页面都是在主进程中创建并维护的。
一个Electron应用有且只有一个主进程。
渲染进程
主进程中,每个创建的页面,都会拥有一个属于自己的渲染进程。不同页面具有不同的渲染进程,因此,一个页面中的数据和操作不会影响到其他页面,这一点与浏览器是一致的。渲染进程中我们可以像开发前端页面一样完成功能,并且可以使用Nodejs相关的各种库。不过,根据操作系统的规定,两个进程之间各自独立,不能直接交互。这意味着,渲染进程不能操作系统相关的接口和事件,也不能直接操作系统GUI。
进程间通信
由于系统级操作需要在主进程中进行,而渲染进程不能直接操作主进程的方法和数据,因此两个进程在协作时需要使用进程间通信。
Electron提供了两种模式来进行进程间通信:ipc库与Remote库
ipcMain与ipcRender
这种模式基于进程间的事件响应。两个库分别用于主进程和渲染进程中。使用时渲染进程发出一个事件,主进程监听同一个事件,并且在消息到来时执行响应的逻辑。我们通常称处理事件响应逻辑的函数为回调函数(Callback function)。相反地,主进程也可以发出一个事件,所有监听了这个事件的渲染进程都会响应这个事件并且执行回调函数中的逻辑。
Remote
这种模式可以理解为远程操控。也就是主进程给渲染进程一个能操控自己的遥控器(remote),这样渲染进程就可以操作主进程中的一切方法了。需要注意的是,这种方式可以使用主进程的方法,但是不能操作主进程中的数据。换句话说,当创建Remote对象时,主进程中的数据会复制出一个副本给渲染进程使用。另外一点需要注意的是,渲染进程中的Remote模块会影响主进程对渲染进程的回收机制。详情请参阅Remote文档。
这种方式会使得渲染进程与主进程的耦合性过高,渲染进程需要了解主进程中的设计规则,并不推荐过多使用Remote。
![Electron应用进程模型示意图](https://i0.wp.com/45.76.71.126/wp-content/uploads/2019/11/electron_process_model.png?resize=837%2C320)
写在最后
在Web应用大行其道之前,桌面应用也拥有曾经辉煌的一天。即便是在当今Web应用,H5小程序遍地开花的时代,桌面应用也依然占据着它的一片空间。
Electron作为一个新兴的桌面应用开发框架,将Web前端页面引入桌面应用,可以说是站在现在Web的肩膀上,推动着桌面应用向新的目标迈进。使用Electron,结合Nodejs和第三方库,开发维护一个应用的成本大大降低了。因此我比较推荐用它来开发一些不需要很高系统性能的应用。需要高性能的应用,比如游戏、视频处理等以及需要与硬件交互的应用,Electron还不适合这些场景。
Electron的未来,还大有可为。不过,相较于Qt等老牌桌面应用开发框架,它的轻量、易用或许才是最大的优势。