在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') }) if (process.env.NODE_ENV === 'development') workerWindow.loadFile(workerURL) // 調試時的加載方式
else workerWindow.loadURL(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接收消息了