在上手ipc通訊以前,得對electron的進程模型有個基本的瞭解,electron中的進程大體能夠分爲主進程和渲染進程,主進程指的就是nodejs的進程,而渲染進程則能夠簡單的理解爲一個Chromium的web頁面。主進程,也就是nodejs進程只有一個,而渲染進程,也就是Chromium的web頁面則能夠有多個,ipc通訊就是在主進程和渲染進程之間通訊。javascript
認爲主進程的代碼是開發者本身寫的,就是普通的node程序,可是渲染進程有可能會加載網頁之類的,可能會執行第三方的js代碼,渲染進程的權限是被限制了的,因此某些敏感操做就須要渲染進程給主進程發消息,讓主進程去作,而後完事了再通知渲染進程。html
在使用electron開發客戶端程序的時候,將其類比爲web端的B/S架構,其渲染進程就是前端的頁面,是門面,而主進程則是服務器後臺,負責處理一些與UI無關的業務邏輯,主進程和渲染進程不可避免的要進行一些數據、指令的交換,即這兩個進程之間要通訊交換數據,這就是進程間通訊,electron提供了ipc模塊用於在主進程和渲染進程之間通訊。前端
渲染進程向主進程發送消息默認就是異步的,在渲染進程的html或者render.js中向主進程發送異步消息:java
const electron = require("electron"); // 第一個參數是約定的事件的名稱,主進程要監聽這個事件 // 第二個及以後的參數是要發送的具體的消息 electron.ipcRenderer.send("render-to-main-message", message);
send方法至少須要兩個參數,第一個是事件名稱,在主線程中須要監聽此事件,而後是至少一個參數的事件參數,能夠有多個,可是至少有一個。node
在主線程main.js中接收事件:web
// 接收從渲染進程發送到主進程的消息 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); });
同步消息是渲染進程向主進程發送的,由於渲染進程頁面能夠有多個,而主進程node進程只有一個,所以渲染進程能夠等主進程,而主進程不能同步等渲染進程。架構
渲染進程向主進程發送同步消息,使用 electron.ipcRenderer.sendSync 方法,這個方法的返回值是從主進程中返回的,在渲染進程render.js中向主進程發送消息:app
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 = "要回復的消息內容"
渲染進程能夠向主進程發送同步消息或者異步消息,可是主進程只能向渲染進程發送異步消息,好比下面是在主進程啓動後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); });
上面的三種發送方式都是隻提取了部分代碼作展現,完整的例子代碼以下:
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"