'One ipcMain.on() works in the same file while the other doesn't work?
I am developing an app using Electron and vue.
I use this solution to communicate between main and render, so I have three files, preload.js
, main and renderer.
// preload.js
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["msgbox", "loadall", "savekv", "saveall"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
}
});
// main
const { ipcMain, dialog } = require('electron')
ipcMain.on("msgbox", (event, args) => dialog.showMessageBox({ message: args }))
ipcMain.on("saveall", (event, config) => dialog.showMessageBox({ message: config }))
// renderer
test() {
window.api.send("saveall", "hahaha"); // <- does not work
window.api.send("msgbox", "haha"); // <- work
}
However, in render file, window.api.send("msgbox", "haha");
works while window.api.send("saveall", "hahaha");
does not.
Electron version 13.6.6 macOS Monterey 12.1
Solution 1:[1]
In theory, there is no reason why both dialog boxes should not show at the same time (hahaha
then haha
).
In reality, I noticed that 50% of the time, only one of the two dialog boxes would show when initially clicking the button
. It was random as to which dialog box would show when only one was displayed. I suspect this may have something to do Javascript's inner workings of the stack and event loop.
To have both dialog boxes show all the time, delaying the display of the second dialog box by only 10ms would work 100% of the time. Additionally, the order of the dialog boxes would always be guaranteed. IE: hahaha
then haha
.
The above results were tested on both Electron v13.6.6 and Electron v18.1.0 (Windows 10) with the below code.
preload.js
(main process)
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
contextBridge.exposeInMainWorld(
'api', {
send: (channel, args) => {
let validChannels = ["msgbox", "loadall", "savekv", "saveall"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
}
}
);
main.js
(main process)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronDialog = require('electron').dialog;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require('path');
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
window.loadFile('index.html')
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ---
electronIpcMain.on('msgbox', (event, args) => {
console.log(args); // Testing
electronDialog.showMessageBox({message: args} )
});
electronIpcMain.on('saveall', (event, config) => {
console.log(config); // Testing
electronDialog.showMessageBox({message: config} )
});
index.html
(render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
</head>
<body>
<input type="button" id="button" value="button">
</body>
<script>
document.getElementeById('button').addEventListener('click', () => {
// Test 1 - Inconsistent results
window.api.send("saveall", "hahaha");
window.api.send("msgbox", "haha");
// Test 2 - Consistent results
// window.api.send("saveall", "hahaha");
// setTimeout(() => { window.api.send("msgbox", "haha"); }, 10);
});
</script>
</html>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | midnight-coding |