Electron食用指南: 简单介绍主线程、渲染线程, 以及常用的通讯方法
Electron是一个使用JavaScript、HTML和CSS构建跨平台桌面应用程序的框架。Electron内嵌了Chromium和Node.js,使得开发者可以使用Web技术和原生API来创建丰富的用户界面和功能。Electron的架构分为两种进程:主线程和渲染线程。本文将介绍这两种进程的作用,以及它们如何与页面进行相互调度。
主线程
主线程是Electron应用程序的入口点,它负责创建和管理应用程序窗口,以及处理与操作系统的交互。主线程可以使用Electron提供的main process API来控制应用程序的生命周期,自定义菜单栏,弹出对话框,注册全局快捷键等。主线程也可以使用Node.js的API来访问文件系统,网络,数据库等资源。主线程只有一个,它运行在主进程中。
以下是一个简单的Electron主线程代码示例:
const { app, BrowserWindow, Menu, dialog } = require('electron'); // 引入Electron模块
let mainWindow = null; // 声明主窗口变量
function createWindow() {
mainWindow = new BrowserWindow({ width: 800, height: 600 }); // 创建主窗口
mainWindow.loadFile('index.html'); // 加载窗口内容
mainWindow.on('closed', () => { mainWindow = null; }); // 监听窗口关闭事件,释放窗口资源
}
app.on('ready', () => {
createWindow(); // 应用程序准备就绪后创建主窗口
const menuTemplate = [ // 定义应用程序菜单栏模板
{
label: 'File',
submenu: [
{ label: 'Open...', accelerator: 'CmdOrCtrl+O', click: () => { // 点击菜单项打开文件选择对话框
dialog.showOpenDialog(mainWindow, { properties: ['openFile'] });
}},
{ label: 'Exit', accelerator: 'CmdOrCtrl+Q', click: () => { app.quit(); }} // 点击菜单项退出应用程序
]
}
];
const menu = Menu.buildFromTemplate(menuTemplate); // 创建菜单栏对象
Menu.setApplicationMenu(menu); // 设置应用程序菜单栏
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') { app.quit(); } // 监听所有窗口关闭事件,退出应用程序
});
app.on('activate', () => {
if (mainWindow === null) { createWindow(); } // 监听应用程序激活事件,如果主窗口不存在则创建它
});
渲染线程
渲染线程是Electron应用程序中负责显示页面内容的进程,它可以使用Electron提供的renderer process API
来与主线程通信,调用原生模块,或者使用Web API来创建动态的用户界面。渲染线程可以有多个,每个渲染线程运行在一个独立的渲染进程中,与浏览器中的标签页类似。每个渲染进程都有自己的内存空间和事件循环,这样可以保证页面之间不会相互影响或干扰。
以下是一个在渲染进程中使用renderer process API
与主线程通信的示例代码:
// 在渲染进程中,可以使用remote模块来访问主线程提供的API
const { remote } = require('electron');
// 获取当前窗口对象
const currentWindow = remote.getCurrentWindow();
// 在渲染进程中发送事件给主线程
currentWindow.webContents.send('message', 'Hello from renderer process!');
// 在渲染进程中监听来自主线程的事件
const { ipcRenderer } = require('electron');
ipcRenderer.on('message', (event, message) => {
console.log(message); // 打印输出 "Hello from main process!"
});
还有哪些交互方式
Electron应用程序中的页面可以通过多种方式进行相互调度,例如:
-
使用IPC(Inter-Process Communication)模块来在主线程和渲染线程之间发送和接收消息。
在渲染进程中,可以使用ipcRenderer模块向主进程发送异步或同步消息,也可以接收主进程发送过来的消息,示例如下:
// 在渲染进程中发送异步消息 const { ipcRenderer } = require('electron') ipcRenderer.send('message', 'Hello from the renderer process!') // 在渲染进程中接收消息 ipcRenderer.on('reply', (event, arg) => { console.log(arg) // prints "Hello from the main process!" })
在主进程中,可以使用ipcMain模块来接收渲染进程发送的消息,并发送回复消息,示例如下:
// 在主进程中接收消息 const { ipcMain } = require('electron') ipcMain.on('message', (event, arg) => { console.log(arg) // prints "Hello from the renderer process!" event.reply('reply', 'Hello from the main process!') })
-
使用remote模块来在渲染线程中直接调用主线程中的对象和方法。(本文已经举过例子了)
-
使用webContents模块来在主线程中操作渲染线程中的页面内容,例如加载URL,执行JavaScript,截图等。
// 在主进程中加载URL const { BrowserWindow } = require('electron') const win = new BrowserWindow({ width: 800, height: 600 }) win.loadURL('https://www.google.com') // 在主进程中执行JavaScript win.webContents.executeJavaScript('alert("Hello from the main process!")') // 在主进程中截图 win.webContents.capturePage().then((image) => { require('fs').writeFile('screenshot.png', image.toPNG(), (err) => { console.log(err) }) })
-
使用BrowserWindow模块来在主线程中创建和管理多个窗口,以及设置窗口之间的父子关系。
// 在主进程中创建窗口 const { BrowserWindow } = require('electron') const parent = new BrowserWindow({ width: 800, height: 600 }) const child = new BrowserWindow({ width: 400, height: 300, parent }) child.loadFile('child.html') // 在主进程中设置父子关系 parent.addOwnedWindow(child)
-
使用BrowserView模块来在主线程中创建和管理多个视图,以及在同一个窗口中显示不同的页面内容。
const { BrowserView } = require('electron'); const view1 = new BrowserView(); const view2 = new BrowserView(); // 将两个BrowserView添加到当前窗口 win.setBrowserView(view1); win.setBrowserView(view2);
然后,可以使用loadURL方法加载不同的URL到不同的BrowserView中:
view1.webContents.loadURL('https://www.google.com'); view2.webContents.loadURL('https://www.github.com');
-
使用webview标签来在渲染线程中嵌入另一个渲染进程,并通过preload脚本和IPC来进行通信。
首先,需要在HTML文件中添加webview标签,并设置preload属性为要加载的脚本文件:
<webview src="https://www.baidu.com" preload="./preload.js"></webview>
然后,在preload.js脚本中,可以使用window.opener来获取对父窗口的引用,并通过IPC通信:
const { ipcRenderer } = require('electron'); // 获取父窗口对象 const parentWindow = window.opener; // 发送消息到父窗口 ipcRenderer.sendTo(parentWindow, 'message-from-webview', 'Hello from webview!');
在父窗口中,可以监听来自webview的消息,并进行相应的处理:
const { ipcMain } = require('electron'); // 监听来自webview的消息 ipcMain.on('message-from-webview', (event, message) => { console.log(`Received message from webview: ${message}`); });
参考资料
转载自:https://juejin.cn/post/7229877486170767420