免费下载案例集|20+数字化领先企业人才培养实践经验 了解详情
写点什么

桌面版应用程序的前世今生

  • 2019-11-04
  • 本文字数:3479 字

    阅读完需:约 11 分钟

桌面版应用程序的前世今生

互联网出现之前,C/S 架构是软件产品的主流,后面渐渐地被 B/S 架构所取代(因为不需要配置客户端),但由于浏览器有刷新机制,服务器的负载等因素,C/S 架构的响应速度和流畅性是好于 B/S 架构的,所以现在软件开发的趋势是两者的融合,一般是 B/S 架构开发的产品可以非常方便地转移到 C/S 架构下。客户端(client)是 C/S 架构软件产品中重要的一部分,除了和用户交互、本地处理数据的强大功能,顺畅的体验和美观的样式也是客户端技术追求的目标。这里和大家介绍桌面版应用程序的一些历史和现在比较流行的 electron 技术。

桌面版应用程序历史

桌面应用程序,又称为 GUI 程序。可以分为以下几个阶段:


  • VB,上古程序员的开发工具,曾经全球第一的开发语言,拖拽式的图形化开发让它成为极佳的桌面开发工具。微软依靠其操作系统的优势,一直压制同时期的竞争对手 delphi。微策略早期应用该技术,开发了管理智能商务平台的大杀器 developer。

  • C++、win32API 的 MFC 方案是基于窗口中组合控件和消息传递机制。这也是 20 多年前的技术,所以 API 设计的不是很友好。几年前微软已经停止维护,简单来说它已经过时了。

  • Winform 微策略几年前基于该技术研发第一代的 Desktop 版本,但是从开发体验角度来说自定义、美化控件会比较麻烦。

  • C# .net framework,代表就是 WPF,它的原生特性是其他类库无法比拟的:High DPI、Split Screen 以及对 DirectX 的天然优势。但是并不开源,需要依赖.net 框架,还有就是启动会比较慢。Workstation Windows 的新客户端就是基于该技术研发。

  • Java swing/javaFx,这是一类比较大的阵营,优势是跨平台和流行开发语言 Java 的天然结合,但开发出来的界面作者个人认为并不美观。

  • C++ Qt,这是很多客户端跨平台的首选,因为开源、UI 库和各种功能的类库非常丰富,但是学习成本比较高。

  • C++ duilib,这是 windows 下开源的 directUI(微软提出的分离 UI 和逻辑的思想)库,它是迎合互联网桌面软件小而美的趋势发展起来的,可能大家对它的关注度比较少。但是用它开发出的产品大名鼎鼎,比如 QQ、微信、爱奇艺等很多知名度高的软件。

  • Objective-c/swift cocoa,这是 mac 平台下的方案。可以方便调用底层的 API,缺点是不跨平台,文档不友好,UI 库并不丰富。现在这种方式开发的越来越少了。

基于 Web 技术的桌面应用开发

从 B/S 和 C/S 架构逐渐融合的角度来说,基于 Web 技术进行桌面程序的开发渐渐变成了主流。因为对界面的代码部分可以做到复用。


这类技术早期的方案是用 vb 内嵌 webBrowser 控件,基于 IE 内核,正好很多网页开发也有用 activeX 的需求,但这种方式具有明显的缺陷——非常依赖于用户的环境,会因为组件缺失导致程序各种崩溃。第二类是嵌入式网页框架,这类技术主要是基于浏览器引擎实现 UI 渲染。比较典型的就是 appkit 上面 UIWebView 和 CEF(chro-mium embeded framework)。这种方法可以使用网页 HTML5+CSS 实现各种酷炫的效果,但是缺点也比较明显,就是桌面程序里面嵌入了一个类似 Chrome 的浏览器,内存的开销会比较大。


后面出现了 nwjs 和 electron,electron 相比 CEF 有了单独执行 js 的 v8 引擎,可以运行 NodeJS 来完成服务器端功能,通过和内部浏览器的 v8 引擎交互可以实现一个独立的客户端,这不同于 CEF 需要寄宿在其他程序内部。

Electron


用 Electron 来做桌面程序开发的优势明显,相当于是完全的网页编程,有 Web 开发经验的前端开发上手非常容易。Web 开发生态广泛,开发成本低,可扩展性强,一些流行的前端框架例如 React、Angular、Vue 都可以和 electron 结合进行开发。另外它也具备和 Qt 一样跨平台的优良特性。对性能要求不高的桌面版程序来说,一份代码同时得到网页版和各个平台的桌面版,开发的效率是其他方案无法比的。可以说,这是大部分人看好的趋势。

和 Web 开发的区别

前端开发的一个痛点就是经常需要考虑多种浏览器之间的兼容,但是使用 electron 开发则不存在这样的问题,它只需要考虑 electron 中对应 Chrome 的版本。另一个使用 electron 解决的痛点是跨域,它可以绕过客户端直接通过 NodeJS 里的 request 通信模块发出请求,这样就无需被跨域所困扰。

扩展能力

node-ffi 可以在 NodeJS 环境中调用动态链接库接口。通过这种方式,我们可以把 JavaScript 方法映射到动态链接库接口,从而实现 C++ 类库的接入。

Electron 运行原理


Electron 的运行机制可以从两种进程说起:主进程和渲染进程。运行 package.json 的称为主进程,它可以负责创建渲染进程(多个)。下图是一段主进程代码,主进程负责创建一个浏览器实例来加载网页。每个创建的浏览器实例都在它自己的渲染进程内返回一个 Web 页面。当 BrowserWindow 实例销毁时,相应的渲染进程也会终止。主进程负责掌管所有的 Web 页面和它们相应的渲染进程。每个渲染进程都是相互独立的,它们只关心自己所运行的 Web 页面。


const electron = require('electron');const app = electron.app;const BrowserWindow = electron.BrowserWindow;
var window = null;
app.on('ready', function() { window = new BrowserWindow({width: 800, height: 600}); window.loadURL('https://microstrategy.com');});
复制代码


主进程还负责应用程序的生命周期(app 打开退出)和一些 app 事件的监听,同时负责系统底层 API 的调用。创建的渲染进程用来展示 HTML + CSS 技术编写的 Web 页面, 同时可以运行 JavaScript 实现交互,可以把渲染进程简单理解为 Chrome 上打开的一个浏览器进程。


<html>  <body>  <script>    const remote = require('electron').remote;    console.log(remote.app.getVersion());  </script>  </body></html>
复制代码


在渲染进程中是不允许调用原生 GUI 相关的 API,那是因为在网页中掌管原生 GUI 很危险,易造成内存泄露。如果你想在网页中进行 GUI 的操作,渲染进程必须向主进程传达请求,然后在主进程中完成操作。


Electron 封装了一系列自己的 API 可供主进程和渲染进程调用。可以通过如下方式获取:


const {app, BrowserWindow, ipcMain, ... } = require('electron'); // 仅主进程可用const {ipcRender, remote, ... } = require('electron'); // 仅渲染进程可用
复制代码


主进程和渲染进程均可直接调用 NodeJS 的 API:


node1.addEventListener('click', () => {   console.log(os.path.basename('xxxx');})
复制代码

进程通信

渲染进程如何向主进程发送消息

通信本质上基于 nodeJS 的事件基础类 Event-Emitter,ipcMain 和 ipcRender 都是该类的实例,通过事件模型需要的接口方法,采用了发布 / 订阅的方式来发送和监听消息。


异步方式:


import { ipcRender } from 'electron'; // 在渲染进程引入 ipcRender,它是 EventEmitter 的一个实例ipcRender.send('async', 'I am from webview'); // 可以异步发送
复制代码


同步方式:


import { ipcRender } from 'electron'; // 在渲染进程引入 ipcRenderipcRender.sendSync('sync', 'I am sync sent from webview'); // 同步方式
复制代码


通过同步方式发送会 block 整个渲染进程,直到主进程响应。


主进程会加载 ipcMain 来进行监听。


import { ipcMain } from 'electron'; // 在主进程引入 ipcMainipcMain.on('async', (event, info) {    console.log(info);});
复制代码


除此以外, electron 还提供了一种简单的方案(remote 模块)来实现渲染进程和主进程的通信。这样就可以不必显示地发送消息。


import { remote } from 'electron'; // 在渲染进程引入 remoteremote.mainProcessObject.invokeMethod(); // 调用主进程才有的方法});
复制代码

主进程如何向渲染进程发送消息

主进程通过找到渲染进程对应的 browserWindow 就可以发送消息。


constant window = BrowserWindow.fromId(global.id); // 通过 id 来进行对应window.webContents.send('msg', 'hello world');
复制代码


渲染进程监听:


ipcRender.on('msg', (event, info) => {    console.log(info)});
复制代码

渲染进程之间共享数据

一种可行的方案是在主进程实现消息的转发。还有比较简单的方案是通过浏览器实现的 HTML API,比如 localStorage, sessionStorage 或者 IndexedDB,或者通过主进程创建全局变量 sharedObject 来实现渲染进程的数据共享。


以上是一些 electron 技术的初步介绍,有兴趣的读者可以继续阅读详细的官方文档来深入学习。目前来看 electron 不能算一个年轻的开源项目, 还有不少新的桌面替代技术在涌现(比如 miniblink)。


作者介绍:


徐瑞青,高级软件工程师,毕业于鲁汶大学电子工程系。2014 年加入微策略,目前在数据 gateway 部门参与数据建模、清洗的开发工作,也参与过 Workstation 数据导入的早期开发。


本文转载自微信公众号:微策略 商业智能


2019-11-04 19:193989

评论 2 条评论

发布
用户头像
管理智能商务平台的大杀器 developer是什么东西?Java的话,RCP更流行吧?
2019-11-04 20:08
回复
没有更多了
发现更多内容

Web & Electron 平台即时通讯产品的技术选型

融云 RongCloud

Web Electron 即时通讯

2022-09-09:给定一个正整数 n,返回 连续正整数满足所有数字之和为 n 的组数 。 示例 1: 输入: n = 5 输出: 2 解释: 5 = 2 + 3,共有两组连续整数([5],[2,

福大大架构师每日一题

算法 rust 福大大

redis数据类型以及它们的底层实现数据结构

想要飞的猪

2022 WAIC 闭幕,融云提供分论坛元宇宙直播技术支持

融云 RongCloud

直播 元宇宙

当代用电行为大赏:有人心疼电费,有人靠屋顶光伏“理财”

脑极体

「工作小记」多个页面的相似操作公共化设计方案

叶一一

前端 设计思维 9月月更

库调多了,都忘了最基础的概念 《锁与线程2终结篇》

知识浅谈

线程 9月月更

云渲染为设计行业带来哪些福利?

3DCAT实时渲染

为什么低代码和专业代码走向融合才能破解低代码困境?

牛刀专业低代码

低代码 低代码平台

Python 教程之变量(1)—— 变量、表达式、条件和函数

海拥(haiyong.site)

Python 9月月更

这个中秋,国潮元宇宙的A新玩法是……?

文心大模型

数据治理(十二):Ranger2.1.0源码编译

Lansonli

数据治理 9月月更

ERP是什么?

优秀

ERP

哈希索引

急需上岸的小谢

9月月更

【JS】防抖与节流---在定义时返回的是回调函数

Sam9029

JavaScript 前端 防抖节流 9月月更

【C语言深度剖析】重点详解函数的形参和实参、传值和传址

Albert Edison

开发语言 传值 C语音 9月月更 传址

Ansible如何使用lookup插件模板化外部数据

山河已无恙

ansible 9月月更

Java进阶(十)tomcat中context配置

No Silver Bullet

tomcat Context 9月月更

LeetCode-316. 去除重复字母&&1081.不同字符的最小子序列(Java实现)

bug菌

9月日更 Leet Code 9月月更

【JS】两种实现-懒加载的方式-附无限滚动案例

Sam9029

JavaScript 前端 懒加载 9月月更

使用 Angular Transfer State 的一个具体例子

汪子熙

typescript 前端开发 angular Web Component 9月月更

「趣学前端」今日祝福不限量,批量导入在路上

叶一一

前端 设计思维 9月月更

C++学习------cmath头文件的源码学习02

桑榆

c++ 9月月更

全球新兴市场移动应用报告

易观分析

移动应用

Nodejs安装及环境配置

nodejs NVM 9月月更

支撑全产业AI,需要怎样的算力服务?

脑极体

Python 教程之数据分析(7)—— Jupyter Notebook 入门

海拥(haiyong.site)

Python 9月月更

Java进阶(十三)servlet监听器

No Silver Bullet

Java Servlet 9月月更

学人工智能难吗?怎么用它赚到钱?

felix

人工智能 赚钱 副业赚钱 算法

LeetCode-448. 找到所有数组中消失的数字(Java)

bug菌

9月日更 Leet Code 9月月更

社招前端二面常见面试题

coder2028

JavaScript 前端

桌面版应用程序的前世今生_大前端_徐瑞青_InfoQ精选文章