📜  ElectronJS 中的进程间通信(IPC)

📅  最后修改于: 2022-05-13 01:56:37.861000             🧑  作者: Mango

ElectronJS 中的进程间通信(IPC)

ElectronJS用于使用能够在 Windows、macOS 和 Linux 操作系统上运行的HTMLCSSJavaScript等 Web 技术构建跨平台原生桌面应用程序。它将 Chromium 引擎和 NodeJS 组合成一个单一的运行时。几个著名的开源项目,如 Visual Studio Code、Slack、Atom、Postman 和 Brave Browser 都是使用 Electron 开发的。
电子可以分为两个主要过程:-

  • 主要流程
  • 渲染器进程

Electron 中的 IPC:单个主进程可以有多个渲染器进程。每个渲染器进程都可以被认为是浏览器中的一个新选项卡。在本教程中,我们将讨论 Electron 如何使用进程间通信 (IPC)在这些进程之间进行通信。 Electron 为我们提供了两个 IPC 模块来帮助进程之间进行通信,

  • ipcMain:此模块用于从主进程到渲染器进程进行通信。它在主进程中定义和使用。它处理从渲染器进程发送的所有同步和异步消息。
  • ipcRenderer:此模块用于从渲染器进程到主进程通信。它在渲染器进程中定义和使用。它提供了向主进程发送消息和从主进程接收消息的能力,同步和异步。

强烈建议不要在渲染器进程中执行繁重的计算,以防止应用程序性能下降和资源密集型。相反,我们应该使用 IPC 将这些任务分配给主进程,让主进程处理应用程序中的任何繁重计算。 IPC中的同步数据传输和异步数据传输有三大区别,

  1. ipc.send()方法用于异步数据传输,而用于同步数据传输则使用ipc.sendSync()方法。
  2. 我们需要专门实现一个回调函数来处理异步数据传输中来自主进程的响应。在同步数据传输的情况下,我们不需要实现回调函数,因为ipc.sendSync()方法将返回数据。
  3. 在主进程( main.js文件)中, win.webContents.send()方法用于异步数据传输。这可以替换为同步数据传输的event.returnValue()方法。

注意:本教程还假设您熟悉上述链接中涵盖的先决条件。
项目结构:让我们从教程的构建块开始,

  • 第一步:检查nodenpm是否安装。如果没有,请访问以下文章:
    • 在 Windows 上安装 Node.js
    • 在 Linux 上安装 Node.js
  • 第 2 步:导航到空目录以设置项目,然后运行以下命令,
npm init
  • 按照给出的步骤生成package.json文件

  • 第 3 步:确保安装了Electron ,如果没有,请立即安装
  • 第四步:根据项目结构创建一个main.js文件。该文件是主进程并充当应用程序的入口点。
javascript
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()
  }
})


html


 

    
    Hello World!
   
    
    

 

    

Hello Geeks!

    
        We are using node         , Chrome         , and Electron         .     
      


html



    
    New Window
    


    
New Window Opened !
          
                


html

Aynschronous Message Sending

    Value Received From Renderer Process -   



javascript
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();
});


javascript
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();
});


javascript
// 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);
});


javascript
// 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 arbitrary Value,display will show as NaN (Not a Number)
    update.innerHTML = Number(arg);
});


html

Synchronous Message Sending

Value Received From Main Process -   



javascript
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  tag
    received.innerHTML = data;
});


javascript
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';
});


  • 第 5 步:src目录中创建index.html文件。 index.html由应用程序启动时的main.js文件在其单独的进程中呈现。每个渲染器进程也可以有自己关联的 CSS 和 JavaScript 文件。
    index.html

html



 

    
    Hello World!
   
    
    

 

    

Hello Geeks!

    
        We are using node         , Chrome         , and Electron         .     
      
  • 第 6 步:要启动 Electron 应用程序,运行命令, “start”是我们在package.json文件中定义的脚本。
npm start
  • 输出:

异步数据传输:由于我们已经设置了基本电子应用程序,让我们定义一个新的 BrowserWindow 实例,它将呈现一个新的网页。这个新网页将成为new-window.html文件。然后我们将实现异步 IPC 以在new-window.html文件和index.html文件之间传递数据。

  • 新窗口.html:

html




    
    New Window
    


    
New Window Opened !
          
                
  • index.html:到目前为止,还没有从应用程序中的任何位置调用此网页。要更改这一点,请将以下代码插入到脚本标记上方的index.html文件中。

html

Aynschronous Message Sending

    Value Received From Renderer Process -   

  • index.js:

javascript

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();
});
  • 输出:有了这个,我们的 GUI 就准备好了。在启动应用程序时。

要使用异步 IPC 将数据从new-window.html中的“input”标签传递到index.html ,请执行以下步骤:

  • 第 1 步:new-window.js文件中,

javascript

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 步:main.js文件中,从 electron 中导入 ipcMain 模块。
const ipcMain = require('electron').ipcMain
  • 在文件末尾添加以下内容,

javascript

// 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 步:index.js文件中,从 electron 导入 ipcRenderer 模块
const ipc = electron.ipcRenderer;
  • 在文件末尾添加以下内容,

javascript

// 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 arbitrary Value,display will show as NaN (Not a Number)
    update.innerHTML = Number(arg);
});
  • 输出:我们已经成功实现了异步 IPC。

同步数据传输:我们现在将在主进程和渲染进程之间实现同步 IPC,并将它们之间的差异可视化,如上所述。

  • 第 1 步:index.html文件中,在按钮标记之后和脚本标记之前添加以下代码。

html


Synchronous Message Sending

Value Received From Main Process -   

  • 第 2 步: “点击我获取同步消息”按钮没有与之关联的功能。我们将通过在index.js文件中添加以下代码来将 EventListener 添加到按钮中。

javascript

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  tag
    received.innerHTML = data;
});
  • 第三步:main.js文件中,在文件末尾添加如下代码,

javascript

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';
});
  • 输出: