在electron-vue中,一般有两个进程:主进程和渲染进程。这两个进程在框架搭建的时候就已经配置好了,它们之间能够正常的互相通讯。但是,由于某些操作比较耗时等原因,我们需要一个后台worker,以避免界面阻塞卡顿的不好体验。调研之后发现,electron可以使用多种后台工作方式:1. webworker;2. 使用隐藏的渲染进程。

webworker有一些优势:编写方便,轻量级。但是缺点是:不能直接使用页面中的数据,node的库函数对多线程支持不安全,打包困难。

使用隐藏的渲染进程优点是可以按照正常的node代码编写,缺点是与主渲染进程交互需要通过主进程来进行。

下面是如何创建隐藏的渲染进程并与另一个渲染进程互相通讯的示例:

首先,需要确定后台渲染进程的html页面位置,我们把它称为worker.html。下面的代码添加在index.js中:

const workerURL = process.env.NODE_ENV === 'development'
  ? `worker.html`
  : `file://${__dirname}/worker.html`

对于开发模式,worker.html会从dist/electron/文件夹下读取。

 接下来在createWindow()中添加如下代码,创建一个隐藏的渲染窗口,为了调试方便,可以将show参数设置为true:

workerWindow = new BrowserWindow({
    show: false,
    webPreferences: { nodeIntegration: true }
  })
  workerWindow.on('closed', () => {
    console.log('background window closed')
  })
  workerWindow.loadFile(workerURL)

为了响应来自两个渲染进程的消息,修改app的on ready回调如下:

app.on('ready', async () => {
  createWindow()
  ipcMain.on('message-from-worker', (event, arg) => {
    sendWindowMessage(mainWindow, 'message-to-renderer', arg)
  })
  ipcMain.on('message-from-renderer', (event, arg) => {
    sendWindowMessage(workerWindow, 'message-from-main', arg)
  })
  ipcMain.on('ready', (event, arg) => {
    console.info('child process ready')
  })
})

message-from-worker表示这个接收到的消息来自后台渲染进程,message-from-renderer表示消息来自前端渲染进程。其中sendWindowMessage是一个向目标窗口发送消息的函数:

function sendWindowMessage(targetWindow, message, payload) {
  if (typeof targetWindow === 'undefined') {
    console.log('Target window does not exist')
    return
  }
  targetWindow.webContents.send(message, payload)
}

在worker.html中,需要实现消息接收响应函数:

<script>
  const { ipcRenderer } = require('electron')

  ipcRenderer.on('message-from-main', (event, arg) => {
    console.info('arg', arg)
  })
</script>

同时,还需要处理完毕的数据返回给主进程,此时通过ipcRenderer.send('message-from-worker', {type:type,data:value})即可完成。

在前端渲染进程中,为了处理方便,我们在main.js中添加了消息路由:

const { ipcRenderer } = require('electron')

let callbackCache = []
Vue.prototype.$ipcRenderer = {
  send: (msgType, msgData) => {
    ipcRenderer.send('message-from-renderer', {
      type: msgType,
      data: msgData
    })
  },
  on: (type, callback) => {
    callbackCache.push({
      type,
      callback
    })
  }
}
ipcRenderer.on('message-to-renderer', (sender, msg) => {
  callbackCache.forEach(cache => {
    if (cache.type === msg.type) {
      cache.callback && cache.callback(msg.data)
    }
  })
}) // 监听主进程的消息

之后,在vue代码中,就可以使用this.$ipcRenderer.send发送消息及this.$ipcRenderer.on接收消息了

04-04 07:37