Межпроцессное взаимодействие (IPC) в ElectronJS

Опубликовано: 4 Января, 2022

ElectronJS используется для создания кроссплатформенных приложений Native Desktop с использованием веб-технологий, таких как HTML , CSS и JavaScript, которые могут работать в операционных системах Windows, macOS и Linux. Он объединяет движок Chromium и NodeJS в единую среду выполнения. Несколько известных проектов с открытым исходным кодом, таких как Visual Studio Code, Slack, Atom, Postman и Brave Browser, разработаны с использованием Electron.

Электрон можно разделить на два основных процесса:

  • Основной процесс
  • Процесс рендеринга

IPC в Electron: один главный процесс может иметь несколько процессов рендеринга. Каждый процесс рендеринга можно рассматривать как новую вкладку в браузере. В этом руководстве мы обсудим, как Electron взаимодействует между этими процессами с помощью межпроцессного взаимодействия (IPC) . Electron предоставляет нам два модуля IPC для связи между процессами,

  • ipcMain: этот модуль используется для обмена данными между основным процессом и процессами рендеринга. Он определен и используется в основном процессе. Он обрабатывает все синхронные и асинхронные сообщения, отправляемые процессом рендеринга.
  • ipcRenderer: этот модуль используется для связи процессов рендерера с основным процессом. Он определен и используется в процессах рендеринга. Он предоставляет возможность отправлять сообщения и получать сообщения от основного процесса, синхронно и асинхронно.

Настоятельно рекомендуется не выполнять тяжелые вычисления в процессах рендеринга, чтобы приложение не замедлилось в производительности и не стало более ресурсоемким. Вместо этого мы должны использовать IPC для распределения этих задач по основному процессу и позволить главному процессу обрабатывать любые тяжелые вычисления в приложении. Между синхронной передачей данных и асинхронной передачей данных в IPC есть три основных различия:

  1. Метод ipc.send () используется для асинхронной передачи данных, тогда как для синхронной передачи данных вместо него используется метод ipc.sendSync ().
  2. Нам нужно специально реализовать функцию обратного вызова для обработки ответа, поступающего от основного процесса при асинхронной передаче данных. В случае синхронной передачи данных нам не нужно реализовывать функцию обратного вызова, поскольку метод ipc.sendSync () вернет данные.
  3. В Основной процесс (файл main.js), метод win.webContents.send () используется для асинхронной передачи данных. Его можно заменить методом event.returnValue () для синхронной передачи данных.

Примечание. В этом руководстве также предполагается, что вы знакомы с предварительными условиями, описанными в вышеупомянутой ссылке.

Структура проекта: начнем со строительных блоков Учебника,

  • Шаг 1. Проверьте, установлены ли node и npm . Если нет, то посетите следующие разделы:
    • Установка Node.js в Windows
    • Установка Node.js в Linux

  • Шаг 2: перейдите в пустой каталог, чтобы настроить проект, и выполните следующую команду,
     npm init

    Следуйте инструкциям по созданию файла package.json.

  • Шаг 3: Убедитесь, что Electron установлен, если нет, то установите его сейчас.
  • Шаг 4: Создайте файл main.js в соответствии со структурой проекта. Этот файл является основным процессом и действует как точка входа в приложение.
    const { app, BrowserWindow } = require( 'electron' )
    let win;
    function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
    nodeIntegration: true
    }
    })
    // and load the index.html of the app.
    win.loadFile( 'src/index.html' )
    // Open the DevTools.
    // win.webContents.openDevTools()
    //Quit app when main BrowserWindow Instance is closed
    win.on( 'closed' , function () {
    app.quit();
    });
    }
    // This method will be called when the Electron has finished
    // initialization and is ready to create browser windows.
    // Some APIs can only be used after this event occurs.
    app.whenReady().then(createWindow)
    // Quit when all windows are closed.
    app.on( 'window-all-closed' , () => {
    // On macOS it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin' ) {
    app.quit()
    }
    })
    app.on( 'activate' , () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) {
    createWindow()
    }
    })
  • Шаг 5: Создайте файл index.html в каталоге src. Index.html отображается в отдельном процессе файлом main.js при запуске приложения. Каждый процесс рендеринга также может иметь свой собственный связанный файл CSS и JavaScript.
    В index.html
    <!DOCTYPE html>
    < html >
    < head >
    < meta charset = "UTF-8" >
    < title >Hello World!</ title >
    < meta http-equiv = "Content-Security-Policy"
    content = "script-src 'self' 'unsafe-inline';" />
    </ head >
    < body >
    < h1 >Hello Geeks!</ h1 >
    < div >
    We are using node
    < script >
    document.write(process.versions.node)
    </ script >, Chrome
    < script >
    document.write(process.versions.chrome)
    </ script >, and Electron
    < script >
    document.write(process.versions.electron)
    </ script >.
    </ div >
    < script src = "index.js" ></ script >
    </ body >
    </ html >
  • Шаг 6: Чтобы запустить приложение Electron, запустите команду, «start» - это сценарий, который мы определили в файле package.json.
     npm start
  • Выход:

Асинхронная передача данных: поскольку мы настроили приложение Basic Electron, давайте определим новый BrowserWindow который будет отображать новую веб-страницу. Эта новая веб-страница будет файлом new-window.html. Затем мы реализуем асинхронный IPC для обмена данными между файлом new-window.html и файлом index.html .

  • новое окно.html:
    <!DOCTYPE html>
    < html lang = "en" >
    < head >
    < meta charset = "UTF-8" >
    < title >New Window</ title >
    < meta http-equiv = "Content-Security-Policy"
    content = "script-src 'self' 'unsafe-inline';" />
    </ head >
    < body >
    < div >New Window Opened !</ div >
    < br >
    < input type = "text" >
    < button id = "submit" >Pass Value to Main Window</ button >
    < script src = "new-window.js" ></ script >
    </ body >
    </ html >
  • index.html: на данный момент эта веб-страница не вызывается из любого места в приложении. Чтобы изменить это, вставьте следующий код в файл index.html прямо над тегом script
    < h3 >Aynschronous Message Sending</ h3 >
    < div >
    Value Received From Renderer Process -
    < span id = "value" ></ span >
    </ div >
    < br >
    < button id = "new" >
    Click Me to Open New Window
    </ button >
  • index.js:
    const electron = require( 'electron' )
    const path = require( 'path' )
    // BrowserWindow Instance is a part of the Main Process,
    // To fetch its instance from the Main Process,
    // Use electron.remote
    const BrowserWindow = electron.remote.BrowserWindow
    var update = document.getElementById( 'value' );
    var button = document.getElementById( 'new' );
    button.addEventListener( 'click' , function (event) {
    // Linking to new-window.html
    const newPath = path.join( ' file:// ' , __dirname, 'new-window.html' );
    let win = new BrowserWindow({
    // To display the Default Frame of the Window
    // consisting of default Menu
    frame: true ,
    // Makes the Renderer Window Sticky,
    // Will always stay on top despite focus change
    alwaysOnTop: true ,
    width: 600,
    height: 400,
    webPreferences: {
    nodeIntegration: true
    }
    });
    // Destroy the BrowserWindow Instance on close
    win.on( 'close' , function () {
    win = null ;
    });
    // win.webContents.openDevTools();
    win.loadURL(newPath);
    win.show();
    });
  • Вывод: На этом наш графический интерфейс готов. При запуске приложения.

    Чтобы передать данные из тега «input» в new-window.html в index.html с помощью асинхронного IPC, выполните следующие действия:

    • Шаг 1. В файле new-window.js
      const electron = require( 'electron' )
      const remote = electron.remote;
      // Import the ipcRenderer Module from Electron
      const ipc = electron.ipcRenderer;
      var input = document.querySelector( 'input' );
      var submit = document.getElementById( 'submit' );
      // Adding Click EventListener to the Button
      submit.addEventListener( 'click' , function () {
      console.log(input.value);
      // Calling the ipcRenderer.send()
      // To send the value from the input tag with
      // a Unique Key to the main process
      // Asynchronously
      ipc.send( 'update-value' , input.value);
      remote.getCurrentWindow().close();
      });
    • Шаг 2: ipcMain модуль ipcMain из файла main.js в файл main.js.
       const ipcMain = require ('электрон'). ipcMain

      Добавьте в конец файла следующее:

      // Responsible for Communication of data from Main
      // process to the Renderer Process
      // Received the value send from the new-window.js file
      // Identifies the data passed based on the Key
      // Which was set in the ipc.send() method in new-window.js file
      ipcMain.on( 'update-value' , function (event, arg) {
      console.log(arg);
      // Passing the data from Main Process to index.html
      // BrowserWindow Instance, value will be received in
      // the index.js based on the Key set here. Using the
      // 'win.webContents.send' method for Asynchronous Data Transfer
      win.webContents.send( 'updateValue' , arg);
      });
    • Шаг 3. ipcRenderer модуль ipcRenderer из файла index.js в файл.
       const ipc = electronic.ipcRenderer;

      Добавьте в конец файла следующее:

      // Using the ipcRenderer.on() method
      // Implementing the Callback Function for Asynchronous IPC,
      // To receive the data based on the key set in the main.js file
      ipc.on( 'updateValue' , function (event, arg) {
      console.log(arg);
      // Updating the value of the HTML Tag with the Data Received
      // In Case the Data Received is not a Number and is
      // some arbitary Value,display will show as NaN (Not a Number)
      update.innerHTML = Number(arg);
      });
    • Результат: мы успешно реализовали асинхронный IPC.

    Синхронная передача данных: теперь мы реализуем синхронный IPC между основным процессом и процессом рендеринга и визуализируем различия между ними, как описано выше.

    • Шаг 1. В файле index.html добавьте следующий код сразу после тега кнопки и перед тегом скрипта.
      < br >
      < h3 >Synchronous Message Sending</ h3 >
      < div >Value Received From Main Process -
      < span id = "received" ></ span >
      </ div >
      < br >
      < button id = "send" >
      Click Me for Synchronous Message
      </ button >
    • Шаг 2. Кнопка «Щелкните меня, чтобы получить синхронное сообщение» не имеет связанных с ней функций. Мы добавим EventListener к кнопке, добавив следующий код в файл index.js.
      var received = document.getElementById( 'received' )
      var button2 = document.getElementById( 'send' );
      // Adding Click EventListener to button2
      // For Synchronous Message Transfer we are using the 'ipc.sendSync' method
      // We do not need to Implemented any Callbacks to handle the Response
      // The 'ipc.sendSync' method will return the data from the Main Process
      button2.addEventListener( 'click' , function (event) {
      // Setting the Key and the Message to be sent to the Main Process
      const data = ipc.sendSync( 'synchronous' , 'Message to Main Window' );
      // Setting the Data received to the <span> tag
      received.innerHTML = data;
      });
    • Шаг 3. В файле main.js добавьте следующий код в конец файла:
      ipcMain.on( 'synchronous' , (event, arg) => {
      // Using this method instead of 'win.webContents.send'
      // for Synchronous Message Transfer
      // The Value of arg = 'Message to Main Window'
      // In case we do not use 'event.returnValue', We will
      // get the following Error
      // 'Uncaught Error: Unable to deserialize cloned data due to
      // invalid or unsupported version.'
      event.returnValue = 'Synchronous Message Sent' ;
      });
    • Выход: