如何在Electron App中运行后台工作进程(Hidden Renderers)
最近使用electron
开发一个图片识别的软件,涉及到后台执行大量的运算,所以这里介绍一种使用Hidden Renderers执行后台进程的一种方式
由于我从接触electron和typescript到写这篇文章只有两天,可能存在错误,请指出
Electron是一个流行的框架,可以使用Web技术(如HTML,CSS和JavaScript)来创建跨平台的桌面应用程序。Electron应用程序由两种类型的进程组成:主进程和渲染进程。主进程负责管理应用程序的生命周期,创建和控制浏览器窗口,以及与操作系统交互。渲染进程负责在浏览器窗口中显示Web页面,并执行其中的JavaScript代码。
有时,我们可能需要在Electron应用程序中运行一些后台工作,例如处理大量数据,执行复杂的计算,或者与远程服务器通信。这些工作可能会消耗大量的CPU和内存资源,从而影响渲染进程的性能和用户体验。为了避免这种情况,我们可以使用后台工作进程来在单独的线程中执行这些工作,从而不干扰主进程和渲染进程。
后台工作进程是一种特殊的渲染进程,它不显示任何Web页面,而是只运行JavaScript代码。它可以通过IPC(Inter-Process Communication)机制与主进程和其他渲染进程通信。Electron提供了两种方式来创建和管理后台工作进程:Web Workers和hidden renderers
hidden renderers是一种特殊类型的渲染进程,它们不显示任何窗口或图形界面,但可以访问Node.js和Electron API,以及Web API。您可以使用hidden renderers来执行任何您想要在后台运行的任务,并通过IPC(进程间通信)与主进程或其他渲染进程交换数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BLnOln21-1680270568043)(https://lzx-figure-bed.obs.dualstack.cn-north-4.myhuaweicloud.com/Figurebed/202303312139422.png)]
- 第一步创建隐藏窗口:
let mainWindow, workerWindow;
function createWindow() {
// 创建主窗口
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: { nodeIntegration: true }
});
mainWindow.loadFile('index.html');
// 创建隐藏的工作窗口
workerWindow = new BrowserWindow({
show: false,
webPreferences: { nodeIntegration: true }
});
workerWindow.loadFile('worker.html');
[...]
}
这是一段使用 Electron 框架创建窗口的代码片段。这段代码创建了两个窗口,一个是主窗口,一个是工作窗口。
代码中的 BrowserWindow 是 Electron 提供的一个类,用于创建桌面应用程序中的窗口。createWindow 函数包含两个 BrowserWindow 对象的创建和配置。
主窗口使用 loadFile 方法加载名为 index.html 的本地 HTML 文件。主窗口的大小被设置为 800x600 像素,并启用了 Node.js 集成,这意味着在主窗口中可以使用 Node.js 模块。
工作窗口也被创建为 BrowserWindow 对象,并使用 loadFile 方法加载名为 worker.html 的本地 HTML 文件。但与主窗口不同的是,工作窗口被设置为不显示,这意味着用户将无法看到该窗口。
- worker.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>I'm a hidden worker</title>
</head>
<body>
<script>
// your background code here
</script>
</body>
</html>
- 第二步进程通信
在 Electron 中,有两种主要的进程类型:主进程和渲染进程。主进程负责管理应用程序的生命周期和与操作系统的交互,而渲染进程则负责显示和交互用户界面。
主进程可以通过渲染进程的 “webContents” 对象与任何渲染进程通信。 “webContents” 对象是渲染进程中显示网页内容的对象,主进程可以使用它来发送消息和监听事件。
渲染进程与主进程之间的通信需要使用 IPC(进程间通信)通道。IPC 通道是一种在 Electron 中用于不同进程之间通信的机制,渲染进程可以使用它来向主进程发送消息和请求数据。
最后,需要注意的是,渲染进程之间不能直接通信。如果两个渲染进程需要通信,它们必须通过主进程进行中转。
- 在工作进程中,我们使用Electron的IPC Renderer模块向主进程发送消息。我们定义了一个名为message2UI的函数,该函数将消息发送到名为message-from-worker的频道,消息本身包含命令和载荷部分。
const electron = require('electron');
const ipcRenderer = electron.ipcRenderer;
function message2UI(command, payload) {
ipcRenderer.send('message-from-worker', { command, payload });
}
message2UI('helloWorld', { myParam: 1337, anotherParam: 42 });
在主进程中,我们需要添加一个处理程序来处理通过message-from-worker通道传入的消息。我们创建了一个名为sendWindowMessage的函数,该函数使用webContents对象将消息转发到目标进程。在app.on(‘ready’)回调中,我们使用IPC Main模块来侦听message-from-worker通道的消息,并将其转发到主窗口(mainWindow)。
const { ipcMain } = require('electron');
function sendWindowMessage(targetWindow, message, payload) {
if(typeof targetWindow === 'undefined') {
console.log('Target window does not exist');
return;
}
targetWindow.webContents.send(message, payload);
}
app.on('ready', () => {
// ...
ipcMain.on('message-from-worker', (event, arg) => {
sendWindowMessage(mainWindow, 'message-from-worker', arg);
});
// ...
});
最后,在渲染进程中,我们需要添加一个监听器来接收通过message-from-worker通道传入的消息。我们可以使用IPC Renderer模块中的on方法来实现这一点。
const { ipcRenderer } = require('electron');
ipcRenderer.on('message-from-worker', (event, arg) => {
console.log(arg.command); // 输出:helloWorld
console.log(arg.payload); // 输出:{ myParam: 1337, anotherParam: 42 }
});