electron進(jìn)程間通信機(jī)制

electronnodejs+chrome內(nèi)核+native層的集成,類似chrome瀏覽器每個(gè)頁(yè)面都屬于一個(gè)進(jìn)程(稱為渲染進(jìn)程),另外還有主進(jìn)程,其提供了如下進(jìn)程間通信機(jī)制:

  1. IPCMain IPCRender通信模塊,其中IPCMain用于主進(jìn)程,IPCRender用于渲染進(jìn)程,這兩者都是node's EventEmiter實(shí)例的封裝;
  • 渲染進(jìn)程->主進(jìn)程

    渲染進(jìn)程通過(guò)IPCRender.send發(fā)送異步消息,IPCRender.sendSync發(fā)送同步消息;主進(jìn)程通過(guò)IPCMain.on接收消息并通過(guò)event.sender.send響應(yīng)異步消息,event.returnValue響應(yīng)同步消息。

    通過(guò)IPCMain與IPCRender模塊可實(shí)現(xiàn)client-server模型,主進(jìn)程作為server端注冊(cè)消息并提供業(yè)務(wù)服務(wù)(如創(chuàng)建窗口、托盤、數(shù)據(jù)持久化訪問(wèn)及設(shè)置等),渲染進(jìn)程作為client端以發(fā)送消息,因此可建立消息與業(yè)務(wù)的分離,業(yè)務(wù)層注冊(cè)可實(shí)現(xiàn)的消息并處理響應(yīng)結(jié)果及返回?cái)?shù)據(jù);

// In main process.
  const {ipcMain} = require('electron')
  ipcMain.on('asynchronous-message', (event, arg) => {
    console.log(arg) // prints "ping"
    event.sender.send('asynchronous-reply', 'pong')
  })

  ipcMain.on('synchronous-message', (event, arg) => {
    console.log(arg) // prints "ping"
    event.returnValue = 'pong'
  })
// In renderer process (web page).
  const {ipcRenderer} = require('electron')
  console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"

  ipcRenderer.on('asynchronous-reply', (event, arg) => {
    console.log(arg) // prints "pong"
  })
  ipcRenderer.send('asynchronous-message', 'ping')

主進(jìn)程->渲染進(jìn)程

主進(jìn)程通過(guò)BrowserWindow.webcontent.send發(fā)送消息,通過(guò)在主進(jìn)程管理所有窗口對(duì)象,可遍歷所有窗口對(duì)象的webcontent屬性來(lái)發(fā)送消息,進(jìn)而可實(shí)現(xiàn)主進(jìn)程向渲染進(jìn)程的廣播消息

注意webContents.on 監(jiān)聽(tīng)的是已經(jīng)定義好的事件,如上面的 did-finish-load。要監(jiān)聽(tīng)自定義的事件還是通過(guò) ipcMainipcRenderer

渲染進(jìn)程的監(jiān)聽(tīng)事件回調(diào)函數(shù)中,也可以通過(guò) event.sender 來(lái)向主進(jìn)程發(fā)送消息。這個(gè)對(duì)象只是 ipcRenderer 的引用(event.sender === ipcRenderer)。因此,event.sender 發(fā)送的消息在主進(jìn)程中還是需要通過(guò) ipcMain.on 方法來(lái)監(jiān)聽(tīng),而不是通過(guò) webContents.on 方法。

  • // In the main process.
      const {app, BrowserWindow} = require('electron')
      let win = null
    
      app.on('ready', () => {
        win = new BrowserWindow({width: 800, height: 600})
        win.loadURL(`file://${__dirname}/index.html`)
        win.webContents.on('did-finish-load', () => {
          win.webContents.send('ping', 'whoooooooh!')
        })
      })
    
    <!-- index.html -->
      <html>
      <body>
        <script>
          require('electron').ipcRenderer.on('ping', (event, message) => {
            console.log(message) // Prints 'whoooooooh!'
          })
        </script>
      </body>
      </html>
    
  1. electron.remote模塊

渲染進(jìn)程可加載remote模塊,并訪問(wèn)主進(jìn)程的模塊或者app對(duì)象,從而使用主進(jìn)程的模塊或者獲取變量,如BrowserWindow、global對(duì)象。

進(jìn)程間通信機(jī)制封裝
可通過(guò)electron提供的通訊機(jī)制接口封裝一套通訊模塊,用于主進(jìn)程與渲染進(jìn)程間通信,基于client-server、訂閱/發(fā)布廣播模型構(gòu)建一套完成的進(jìn)程間消息機(jī)制,消息機(jī)制流程(可參考)如下:

image.png

渲染進(jìn)程加載本地js文件
渲染進(jìn)程需要加載本地的IPC Clientjs文件已實(shí)現(xiàn)進(jìn)程間通信,可通過(guò)如下方式實(shí)現(xiàn):

  • 使用browserwindow.webPreferences.preload指定需要加載的js文件

  • 使用browserwindow.webcontent.executejavascript()接口

使用executejavascript方式存在時(shí)序問(wèn)題,因其加載晚于webcontent加載渲染頁(yè)面,而preload方式要早于webcontent頁(yè)面加載;

BrowserWindow對(duì)象都有唯一的窗口ID(可通過(guò)getCurrentWindow來(lái)獲?。?,若是基于業(yè)務(wù)需要設(shè)置綁定不同的ID,可通過(guò)此唯一的ID綁定需要設(shè)置的ID,并通過(guò)remote模塊獲取對(duì)應(yīng)關(guān)系,以解決BrowserWindow對(duì)象通過(guò)executejavascript時(shí)序問(wèn)題;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容