Electron進程間通信的實現
使用Electron開發出來的桌面應用都是多進程的,其中包含瞭一個主進程(Main)和至少一個渲染進程(Renderer)。
主進程控制整個應用的生命周期,通過electron中的一些模塊與GUI交互,同時控制每一個渲染進程。
渲染進程會在BrowserWindow對象創建出的窗口中渲染出Web頁面,每個渲染頁面都運行在獨立的進程中。
主進程與渲染進程之間通信
ipc模塊 + window.webContents
ipc模塊包含ipcMain和 ipcRenderer兩個模塊,其中ipcMain在主進程中使用,ipcRenderer在渲染進程中使用,在使用之前,要使用require引入對應的模塊。
ipc模塊中的方法:
- ipcMain.on(msg, () => {}):監聽渲染進程發送的msg消息,並做出響應。
- ipcMain.once(msg, () => {}):監聽渲染進程發送的msg消息,並做出響應,但是監聽到一次msg事件後自動移除這個監聽器。
- ipcRenderer.on(msg, () => {}):監聽主進程發送的msg消息,並做出響應。
- ipcRenderer.once(msg, () => {}):監聽主進程發送的msg消息,並做出響應,但是監聽到一次msg事件後自動移除這個監聽器。
- ipcRenderer.send(msg, data):監聽渲染進程向主進程發送msg異步消息,並攜帶參數data。
- ipcRenderer.sendSync(msg, data):監聽渲染進程向主進程發送msg同步消息,並攜帶參數
- ipcRenderer.sentTo(webContentId, msg, data):監聽渲染進程向具有webContentId的窗口發送消息
- ipcRenderer.sendToHost(msg, data):監聽渲染進程向host頁面上的 <webview> 元素發送消息
ipc模塊還提供瞭刪除指定監聽器和刪除所有監聽器的方法:removeListener()、removeAllListener(),這兩個方法在ipcMain和ipcRenderer這兩個模塊中的用法是一樣的。
通過上面的幾個監聽器我們發現,單獨使用ipc模塊無法實現主進程主動向渲染進程發送消息。所以我一般把BrowserWindow實例中的webContents和ipc模塊結合使用
一個主進程與渲染進程間通信的例子
// 在主進程中使用ipcMain const { ipcMain, BrowserWindow } = require('electron'); window = new BrowserWindow({ width: 800, height: 600 }); // 主進程主動向渲染進程發送消息 window.webContents.send('main webContents msg', data); // 主進程接收渲染進程發送的消息,並通過回調函數做出響應 ipcMain.on('renderer ipc msg', (event, arg) => { // TODO something })
// 在渲染進程中使用ipcRender const ipcRender = require('electron'); // 渲染進程中使用ipcRenderer.on接收主進程消息,並通過回調函數做出相應 ipcRenderer.on('main webContents msg', (event, arg) => { // 在相應主進程事件時,通過ipcRenderer.send方法像主進程發送另一條消息 ipcRenderer.send('renderer ipc msg', data); })
ipcRenderer發送的同步消息和異步消息
在上面列舉的幾個方法中,其中ipcRenderer發送消息的方法分為發送同步消息的方法ipcRenderer.send和發送異步消息的方法ipcRenderer.sendSync。主程序在監聽到這兩種不同方法的消息時,可以通過不同的方式給渲染進程返回消息:
// 渲染進程 // 渲染進程發送異步消息 ipcRenderer.send('msg', data); // 渲染進程發送同步消息。 發送同步消息,任務未完成時會阻止其他操作 var message = ipcRenderer.sendSync('sync msg', data);
ipcMain.on('msg', (event, arg) => { // 主進程監聽到渲染進程發的異步消息後,通過event.sender.send()的方式進行響應,可以在渲染進程中使用ipcRenderer.on監聽'return msg'消息 event.sender.send('return msg', data) }) ipcMain.on('sync msg', (event, arg) => { event.retuenValue = 'msg'; })
remote模塊
在渲染進程中使用remote,可以調用主進程所提供的一些方法。(例如:dialog、menu等模塊)
const { BrowserWindow } = require('electron').remote; //通過remote模塊,可以在渲染進程中調用BrowserWindow模塊 let win = new BrowserWindow({ width: 800, height: 600}); win.loadURL('index.html');
渲染進程中使用remote模塊返回的對象,都代表瞭主進程中的一個對象,一般稱為遠程對象。調用遠程對象的方法時,實際上是在想主進程發送同步消息。
比如上面的代碼中,BrowserWindow實例是通過remote模塊返回的,所以渲染進程中的BrowserWindow和win都是遠程對象。在執行new BrowserWindow({…})這段代碼的時候,並沒有在渲染進程中創建BrowserWindow實例的對象,而是在主進程中創建瞭BrowserWindow對象,並把這個對象返回到渲染進程中。
remote的方法和屬性
- remote.require(module):返回主進程中的對象
- remote.getCurrentWindow():返回此網頁所屬的窗口
- remote.getGlobal(name):返回主進程中name的全局變量
- remote.process:返回主進程中的process對象
渲染進程之間通信
上面提到的通信方法,經過測試發現都無法在渲染進程之間直接通信,有時候我們開發中可以使用主進程作為中轉進行渲染進程間的通信:
// renderer process A const { ipcRenderer } = require('electron'); ipcRenderer.send('A send msg', data);
// main process const { ipcMain, BrowserWindow } = require('electron'); let win = new BrowserWindow({...}); ipcMain.on('A send msg', (event ,arg) => { // TODO something win.webContents.send('main send msg', data); })
const { ipcRenderer } = require('electron'); ipcRenderer.on('main send msg', (event, arg) => { // TODO something })
除瞭上面這種需要main process中轉的方式之外,還有一種方式能夠實現渲染進程之間的直接通信:
// main process // 兩個窗口互相獲取對方的窗口 id, 並發送給渲染進程 const { BrowserWindow} = require('electron'); let win1 = new BrowserWindow({...}); let win2 = new BrowserWindow({...}); win1.webContents.send('distributeIds',{ win2Id : win2.id }); win2.webContents.send('distributeIds',{ win1Id : win1.id });
// renderer process const { remote } = require('electron').remote; // fromId() 可以根據窗口id找到目標窗口 remote.BrowserWindow.fromId(win2Id).webContents.send('msg', data);
到此這篇關於Electron進程間通信的實現的文章就介紹到這瞭,更多相關Electron進程間通信內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- vue + electron應用文件讀寫操作
- vue + Electron 制作桌面應用的示例代碼
- electron創建新窗口模態框並實現主進程傳值給子進程
- 聊聊vue番茄鐘與electron 打包問題
- electron原理,以及electron生成可執行文件的方法實例分析 原創