轉載來自:https://www.cnblogs.com/cc11001100/p/14290450.html
一、主進程和渲染進程
1.1 主進程和渲染進程的概念
在上手ipc通信之前,得對electron的進程模型有個基本的了解,electron中的進程大致可以分為主進程和渲染進程,主進程指的就是nodejs的進程,而渲染進程則可以簡單的理解為一個Chromium的web頁面。主進程,也就是nodejs進程只有一個,而渲染進程,也就是Chromium的web頁面則可以有多個,ipc通信就是在主進程和渲染進程之間通信。
1.2 主進程和渲染進程的環境區別
認為主進程的代碼是開發者自己寫的,就是普通的node程序,但是渲染進程有可能會加載網頁之類的,可能會執行第三方的js代碼,渲染進程的權限是被限制了的,所以某些敏感操作就需要渲染進程給主進程發消息,讓主進程去做,然后完事了再通知渲染進程。
在使用electron開發客戶端程序的時候,將其類比為web端的B/S架構,其渲染進程就是前端的頁面,是門面,而主進程則是服務器后台,負責處理一些與UI無關的業務邏輯,主進程和渲染進程不可避免的要進行一些數據、指令的交換,即這兩個進程之間要通信交換數據,這就是進程間通信,electron提供了ipc模塊用於在主進程和渲染進程之間通信。
二、主進程與渲染進程通信
2.1 渲染進程向主進程發送異步消息
渲染進程向主進程發送消息默認就是異步的,在渲染進程的html或者render.js中向主進程發送異步消息:
const electron = require("electron"); // 第一個參數是約定的事件的名稱,主進程要監聽這個事件 // 第二個及之后的參數是要發送的具體的消息 electron.ipcRenderer.send("render-to-main-message", message);
send方法至少需要兩個參數,第一個是事件名稱,在主線程中需要監聽此事件,然后是至少一個參數的事件參數,可以有多個,但是至少有一個。
在主線程main.js中接收事件:
// 接收從渲染進程發送到主進程的消息 ipcMain.on("render-to-main-message", (event, message) => { // 在控制台上打印一下 console.log(`receive message from render: ${message}`); // 回復消息 event.reply("main-to-render-message", `來自主進程:我收到了你的消息“${message}”`); })
使用 event.reply 在主進程中回復渲染進程發過來的消息,因為這個replay指定了一個事件名稱,因此在渲染進程render.js中也要監聽事件才能收到回復:
// 接收主進程發來的消息 // 第一個參數是約定的事件的名稱 // 第二個參數是處理事件的callback electron.ipcRenderer.on("main-to-render-message", (event, message) => { alert(message); });
2.2 渲染進程向主進程發送同步消息
同步消息是渲染進程向主進程發送的,因為渲染進程頁面可以有多個,而主進程node進程只有一個,因此渲染進程可以等主進程,而主進程不能同步等渲染進程。
渲染進程向主進程發送同步消息,使用 electron.ipcRenderer.sendSync 方法,這個方法的返回值是從主進程中返回的,在渲染進程render.js中向主進程發送消息:
const electron = require("electron"); // 發送同步消息 const replayMessage = electron.ipcRenderer.sendSync("render-to-main-message-sync", message); alert(replayMessage);
在主進程main.js中接收並回復渲染進程發過來的同步消息:
// 接收同步消息 ipcMain.on("render-to-main-message-sync", (event, message) => { // 控制台打印一下知道來了 console.log(`receive sync message from render: ${message}`); // 回復渲染進程的同步消息 event.returnValue = `來自主進程:我收到了你的消息“${message}”`; })
在主進程中對於同步消息和異步消息的接收沒有區別,只是回復同步消息的時候變成了:
event.returnValue = "要回復的消息內容"
2.3 主進程向渲染進程發送消息
渲染進程可以向主進程發送同步消息或者異步消息,但是主進程只能向渲染進程發送異步消息,比如下面是在主進程啟動后3秒向渲染進程發送一條消息:
function createWindow() { const window = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } }) // 注意這個路徑是從項目根路徑開始的 window.loadFile("example/use-ipc/index.html") setTimeout(() => { window.webContents.send("main-to-render-message", "啟動完成了"); }, 3000) }
在渲染進程render.js中監聽此事件:
const electron = require("electron"); electron.ipcRenderer.on("main-to-render-message", (event, message) => { alert(message); });
2.4 代碼及運行效果一覽
上面的三種發送方式都是只提取了部分代碼做展示,完整的例子代碼如下:
main.js:
const {app, BrowserWindow, ipcMain} = require("electron") function createWindow() { const window = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } }) // 注意這個路徑是從項目根路徑開始的 window.loadFile("example/use-ipc/index.html") setTimeout(() => { window.webContents.send("main-to-render-message", "啟動完成了"); }, 3000) } app.whenReady().then(createWindow) app.on("window-all-closed", () => { if (process.platform !== "darwin") { app.quit() } }) app.on("activate", () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) // 接收從渲染進程發送到主進程的消息 ipcMain.on("render-to-main-message", (event, message) => { // 在控制台上打印一下 console.log(`receive message from render: ${message}`); // 回復消息 event.reply("main-to-render-message", `來自主進程:我收到了你的消息“${message}”`); }) // 接收同步消息 ipcMain.on("render-to-main-message-sync", (event, message) => { // 控制台打印一下知道來了 console.log(`receive sync message from render: ${message}`); // 回復渲染進程的同步消息 event.returnValue = `來自主進程:我收到了你的消息“${message}”`; })
index.html文件(render.js沒有單獨提出來,render的js直接放到html中了):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>IPC通信</title> </head> <body> <h1>IPC通信</h1> <input type="text" id="message"> <button onclick="sendMessageToMainProcess()">發送消息給主進程</button> <script type="text/javascript"> const electron = require("electron"); // 接收主進程發來的消息 // 第一個參數是約定的事件的名稱 // 第二個參數是處理事件的callback electron.ipcRenderer.on("main-to-render-message", (event, message) => { alert(message); }); // 向主進程發送消息 function sendMessageToMainProcess() { const message = document.getElementById("message").value; // 第一個參數是約定的事件的名稱,主進程要監聽這個事件 // 第二個及之后的參數是要發送的具體的消息 electron.ipcRenderer.send("render-to-main-message", message); // 發送同步消息 const replayMessage = electron.ipcRenderer.sendSync("render-to-main-message-sync", message); alert(replayMessage); } </script> </body> </html> 效果:
本文所用Electron版本:"electron": "^11.1.0"