454 Wörter
2 Minuten
Electron IPC - async / sync

IPC Interproesskommunikation#

Eine Electron-App hat immer einen Main-Prozess und kann unendlich viele Render-Prozesse besitzen. Zugriff auf die nativen Desktop-APIs (z.B.: Dateisystem) hat aber aus Sicherheitsgründen nur der Main-Prozess. Damit man aber dennoch (auch mit den Render-Prozessen) sicher auf die APIs “zugreifen” kann, nutzt Electron das IPC-Modell mit den IPC-Objekten um Informationen zwischen dem Main- und den Render-Prozessen austauschen zu können.

Synchrones IPC / Asyncron IPC#

Synchrones IPC blockt andere Systemoperationen solange bis es selbst seine Aufgabe komplett beendet hat. Asynchrones IPC hingegen, lässt andere Prozesse gewähren und sollte daher bevorzugt verwendet werden.

Das remote-Modul arbeitet immer syncron und kann daher zu prozessualen Problemen und eingeschränkter Performance führen.

Webpreferences#

Wenn du in den webPreferences die Option nodeIntegration: true gewählt hast, kannst du alle beliebigen Node-Module und nativen Desktop-APIs im Frontend deiner Anwendung nutzen.

Beispiel#

Nun ein Beispiel (asynchrones IPC):

In der main.js musst du das ipcMain-Modul hinzufügen:

const { app, BrowserWindow, ipcMain} = require("electron");

in der routing.js musst du das ipcRenderer-Modul hinzufügen:

const { app, BrowserWindow, ipcRenderer} = require("electron");

Der Renderprozess soll nun auf ein Klick-Event reagieren und eine IPC-Anfrage an den Main-Prozess senden. Dazu muss in die main.js folgende const deklariert werden:

const error = document.getElementById('error')

error.addEventListener('click', function (event){
    ipcRenderer.send('mitteilung')
})

Damit der main-Prozess die Mitteilung auch empfangen kann, musst du folgendes in die main.js einfügen:

ipcMain.on('mitteilung', function(event){
  dialog.showErrorBox('IPC Error', 'Mitteilung erhalten!')
})

Damit kannst du das IPC-Modell schon auf einfachste Art ausprobieren.

Um nun aber eine Nachricht vom Main-Prozess an den Renderprozess schicken zu können, musst du folgendes in der ipcMain.on(...) von oben ergänzen:

ipcMain.on('mitteilung', function(event){
  dialog.showErrorBox('IPC Error', 'Mitteilung erhalten!')                        

  event.sender.send('mitteilung 2', 'Main-Prozess hat die Nachricht erhalten!')
})

Damit du das Event auch abfangen kannst, musst du noch im Render-Prozess auf die eingehende Nachricht ('mitteilung 2') auf dem Event-Kanal achten.

Dazu musst du in der routing.js nun noch folgende Funktion zum Anzeigen der Nachricht hinzufügen:

ipcRenderer.on('mitteilung 2', function(event, arg){
    document.write("<p>"+arg+"</p>")
})

Kurz-Beispiel sync/async (kompletter Code)#

index.html

<!DOCTYPE html>
<html>
  <head>
    meta charset="UTF-8">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <title>ASYNC / SYNC</title>
  </head>
  <body>
    <h1>IPC-Modell</h1>
    <button id="asyncButton" type="button" class="btn btn-info">asyncButton</button>
    <button id="syncButton" type="button" class="btn btn-info">syncButton</button>
    <script src="js/routing.js"></script>
  </body>
</html>

routing.js

const {app, BrowserWindow, ipcRenderer} = require('electron');
const asyncButton = document.getElementById('asyncButton')
const syncButton = document.getElementById('syncButton')

asyncButton.addEventListener('click', function (event){
    console.log('sync1')
    ipcRenderer.send('async-mitteilung')
    console.log('sync2')
})

syncButton.addEventListener('click', function (event){
    console.log('sync1')
    console.log(ipcRenderer.sendSync('sync-mitteilung'))
    console.log('sync2')
})

ipcRenderer.on('async-antwort', function(event, arg){
    console.log(arg)
})

main.js

const { app, BrowserWindow, ipcMain, dialog} = require("electron");
const { MenuItem } = require("electron/main");
const remote = require('@electron/remote/main')
remote.initialize()
const path = require("node:path");

function createWindow() {
  const mainWindow = new BrowserWindow({
    icon: "assets/icons/app_icon.png",
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
      enableRemoteModule: true
    },
  });
  mainWindow.loadFile("src/index.html");
}

// ASYNC
ipcMain.on('async-mitteilung', function(event){
  event.sender.send('async-antwort', 'Main-Prozess hat die Nachricht erhalten!')
})

// SYNC
ipcMain.on('sync-mitteilung', function(event){
  event.returnValue = "Sync Antwort!!"
})

app.whenReady().then(() => {
  createWindow();

  app.on("activate", function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

app.on("window-all-closed", function () {
  if (process.platform !== "darwin") app.quit();
});atform !== "darwin") app.quit();
});
Electron IPC - async / sync
https://www.couchidee.com/posts/electron-sync-async/
Autor
Christian Böhm
Veröffentlicht am
2024-04-01