Electron 主进程与渲染进程的通信

简介

ipcMain 模块管理主进程到渲染进程的异步通信

ipcRenderer模块管理从渲染器进程到主进程的异步通信。

ipcMain

从主进程到渲染进程的异步通信。

进程:主进程

ipcMain 是一个 EventEmitter 的实例。 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息。 从渲染器进程发送的消息将被发送到该模块。

EN

发送消息

也可以从主进程向渲染进程发送消息,查阅ebContents.send获取更多信息。

  • 发送消息时,事件名称为channel
  • 回复同步信息时,需要设置event.returnValue
  • 可以使用event.reply(...)将异步消息发送回发送者。 This helper method will automatically handle messages coming from frames that aren't the main frame (e.g. iframes) whereas event.sender.send(...) will always send to the main frame.

下面是在渲染和主进程之间发送和处理消息的一个例子:

// 在主进程中.
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.reply('asynchronous-reply', 'pong')
})

ipcMain.on('synchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.returnValue = 'pong'
})

//在渲染器进程 (网页) 中。
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"

ipcRenderer.on('asynchronous-reply', (event, arg) => {
  console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')

EN

方法

IpcMain模块有以下方法来侦听事件:

EN

ipcMain.on(channel, listener)

  • channel String

  •   listener
    

    Function

    • event IpcMainEvent
    • ...args any[]

监听 channel,当接收到新的消息时 listener 会以 listener(event, args...) 的形式被调用。

EN

ipcMain.once(channel, listener)

  • channel String

  •   listener
    

    Function

    • event IpcMainEvent
    • ...args any[]

Adds a one time listener function for the event. This listener is invoked only the next time a message is sent to channel, after which it is removed.

EN

ipcMain.removeListener(channel, listener)

  • channel String

  •   listener
    

    Function

    • ...args any[]

从监听器数组中移除监听 channel 的指定 listener

EN

ipcMain.removeAllListeners([channel])

  • channel String (optional)

删除所有监听者,或特指的 channel 的所有监听者.

EN

ipcMain.handle(channel, listener)

  • channel String
  • listener Function<Promise | any>event IpcMainInvokeEvent...args any[]

Adds a handler for an invokeable IPC. This handler will be called whenever a renderer calls ipcRenderer.invoke(channel, ...args).

If listener returns a Promise, the eventual result of the promise will be returned as a reply to the remote caller. Otherwise, the return value of the listener will be used as the value of the reply.

// Main process
ipcMain.handle('my-invokable-ipc', async (event, ...args) => {
  const result = await somePromise(...args)
  return result
})

// Renderer process
async () => {
  const result = await ipcRenderer.invoke('my-invokable-ipc', arg1, arg2)
  // ...
}
复制

The event that is passed as the first argument to the handler is the same as that passed to a regular event listener. It includes information about which WebContents is the source of the invoke request.

EN

ipcMain.handleOnce(channel, listener)

  • channel String
  • listener Function<Promise | any>event IpcMainInvokeEvent...args any[]

Handles a single invokeable IPC message, then removes the listener. See ipcMain.handle(channel, listener).

EN

ipcMain.removeHandler(channel)

  • channel String

Removes any handler for channel, if present.

EN

IpcMainEvent object

The documentation for the event object passed to the callback can be found in the ipc-main-event structure docs.

EN

IpcMainInvokeEvent object

The documentation for the event object passed to handle callbacks can be found in the ipc-main-invoke-event structure docs.

ipcRenderer

从渲染器进程到主进程的异步通信。

进程: Renderer

ipcRenderer 是一个 EventEmitter 的实例。 你可以使用它提供的一些方法从渲染进程 (web 页面) 发送同步或异步的消息到主进程。 也可以接收主进程回复的消息。

请从 ipcMain 查看代码示例。

EN

方法

ipcRenderer 模块使用以下方法来监听事件和发送消息。

EN

ipcRenderer.on(channel, listener)

  • channel String

  •   listener
    

    Function

    • event IpcRendererEvent
    • ...args any[]

监听 channel,当接收到新的消息时 listener 会以 listener(event, args...) 的形式被调用。

EN

ipcRenderer.once(channel, listener)

  • channel String

  •   listener
    

    Function

    • event IpcRendererEvent
    • ...args any[]

Adds a one time listener function for the event. This listener is invoked only the next time a message is sent to channel, after which it is removed.

EN

ipcRenderer.removeListener(channel, listener)

  • channel String

  •   listener
    

    Function

    • ...args any[]

从监听器数组中移除监听 channel 的指定 listener

EN

ipcRenderer.removeAllListeners(channel)

  • channel String

移除所有的监听器,当指定 channel 时只移除与其相关的所有监听器。

EN

ipcRenderer.send(channel, ...args)

  • channel String
  • ...args any[]

通过channel向渲染器进程发送异步消息,可以发送任意参数。 Arguments will be serialized with the Structured Clone Algorithm, just like [window.postMessage][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception.

NOTE: Sending non-standard JavaScript types such as DOM objects or special Electron objects is deprecated, and will begin throwing an exception starting with Electron 9.

The main process handles it by listening for channel with the ipcMain module.

If you need to transfer a [MessagePort][] to the main process, use ipcRenderer.postMessage.

If you want to receive a single response from the main process, like the result of a method call, consider using ipcRenderer.invoke.

EN

ipcRenderer.invoke(channel, ...args)

  • channel String
  • ...args any[]

Returns Promise<any> - Resolves with the response from the main process.

Send a message to the main process via channel and expect a result asynchronously. Arguments will be serialized with the Structured Clone Algorithm, just like [window.postMessage][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception.

NOTE: Sending non-standard JavaScript types such as DOM objects or special Electron objects is deprecated, and will begin throwing an exception starting with Electron 9.

The main process should listen for channel with ipcMain.handle().

例如:

// Renderer process
ipcRenderer.invoke('some-name', someArgument).then((result) => {
  // ...
})

// Main process
ipcMain.handle('some-name', async (event, someArgument) => {
  const result = await doSomeWork(someArgument)
  return result
})
复制

If you need to transfer a [MessagePort][] to the main process, use ipcRenderer.postMessage.

If you do not need a response to the message, consider using ipcRenderer.send.

EN

ipcRenderer.sendSync(channel, ...args)

  • channel String
  • ...args any[]

返回 any - 由 ipcMain 处理程序发送过来的值。

Send a message to the main process via channel and expect a result synchronously. Arguments will be serialized with the Structured Clone Algorithm, just like [window.postMessage][], so prototype chains will not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception.

NOTE: Sending non-standard JavaScript types such as DOM objects or special Electron objects is deprecated, and will begin throwing an exception starting with Electron 9.

主进程可以使用 ipcMain 监听 channel来接收这些消息,并通过 event.returnValue 设置回复消息。

⚠️ WARNING: Sending a synchronous message will block the whole renderer process until the reply is received, so use this method only as a last resort. It's much better to use the asynchronous version, invoke().

EN

ipcRenderer.postMessage(channel, message, [transfer])

  • channel String
  • message any
  • transfer MessagePort[] (optional)

Send a message to the main process, optionally transferring ownership of zero or more [MessagePort][] objects.

The transferred MessagePort objects will be available in the main process as MessagePortMain objects by accessing the ports property of the emitted event.

例如:

// Renderer process
const { port1, port2 } = new MessageChannel()
ipcRenderer.postMessage('port', { message: 'hello' }, [port1])

// Main process
ipcMain.on('port', (e, msg) => {
  const [port] = e.ports
  // ...
})
复制

For more information on using MessagePort and MessageChannel, see the MDN documentation.

EN

ipcRenderer.sendTo(webContentsId, channel, ...args)

  • webContentsId Number
  • channel String
  • ...args any[]

Sends a message to a window with webContentsId via channel.

EN

ipcRenderer.sendToHost(channel, ...args)

  • channel String
  • ...args any[]

就像 ipcRenderer.send,不同的是消息会被发送到 host 页面上的 <webview> 元素,而不是主进程。

EN

事件对象

The documentation for the event object passed to the callback can be found in the ipc-renderer-event structure docs.

案例

主进程渲染进程通信

主进程

//为了管理应用程序的生命周期事件以及创建和控制浏览器窗口,您从 electron 包导入了 app 和 BrowserWindow 模块 。
const { app, BrowserWindow,ipcMain } = require('electron')

//在此之后,你定义了一个创建 新的浏览窗口的函数并将 nodeIntegration 设置为 true,将 index.html 文件加载到窗口中(第 12 行,稍后我们将讨论该文件)
function createWindow () {
    const win = new BrowserWindow({
         800,
        height: 600,
        webPreferences: {
            //是否注入nodeapi
            nodeIntegration: true,
            //渲染进程是否启用remote模块
            enableRemoteModule: true
        }
    })

    win.loadFile('index.html')
}
//你通过调用 createWindow方法,在 electron app 第一次被初始化时创建了一个新的窗口。
app.whenReady().then(createWindow)

//您添加了一个新的侦听器,当应用程序不再有任何打开窗口时试图退出。 由于操作系统的 窗口管理行为 ,此监听器在 macOS 上是禁止操作的
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

//您添加一个新的侦听器,只有当应用程序激活后没有可见窗口时,才能创建新的浏览器窗口。 例如,在首次启动应用程序后或重启运行中的应用程序
app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
        createWindow()
    }
})

//监听
ipcMain.on('send-message-to-main-test', (event, arg) => {
    console.log('主线程接收到的消息:',arg)

    //返回响应的事件
    event.reply('send-message-to-render-test','来自主进程的问候')

})

渲染进程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>进程通信</title>
</head>
<body>
<h1>进程通信</h1>
<button onclick="sendMessageMain()">发送信息给主进程</button>
</body>
<script>
    const { ipcRenderer } = require('electron');
    function sendMessageMain(){
        //发送
        ipcRenderer.send('send-message-to-main-test', '这是来自渲染进程的数据66666')

    }

    //监听
    ipcRenderer.on('send-message-to-render-test', (event, arg) => {
        console.log('渲染进程收到的消息:',arg)
    })
</script>
</html>

image-20210204152000221

主进程主动给渲染进程发消息

主进程

//为了管理应用程序的生命周期事件以及创建和控制浏览器窗口,您从 electron 包导入了 app 和 BrowserWindow 模块 。
const { app, BrowserWindow,ipcMain } = require('electron')

//在此之后,你定义了一个创建 新的浏览窗口的函数并将 nodeIntegration 设置为 true,将 index.html 文件加载到窗口中(第 12 行,稍后我们将讨论该文件)
function createWindow () {
    const win = new BrowserWindow({
         800,
        height: 600,
        webPreferences: {
            //是否注入nodeapi
            nodeIntegration: true,
            //渲染进程是否启用remote模块
            enableRemoteModule: true
        }
    })

    win.loadFile('index.html')

    //5s后 , 主动发送
    setTimeout(()=>{
        win.webContents.send('send-message-to-render-test', '这是主进程的主动搭讪')
    }, 5000)
}
//你通过调用 createWindow方法,在 electron app 第一次被初始化时创建了一个新的窗口。
app.whenReady().then(createWindow)

//您添加了一个新的侦听器,当应用程序不再有任何打开窗口时试图退出。 由于操作系统的 窗口管理行为 ,此监听器在 macOS 上是禁止操作的
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

//您添加一个新的侦听器,只有当应用程序激活后没有可见窗口时,才能创建新的浏览器窗口。 例如,在首次启动应用程序后或重启运行中的应用程序
app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
        createWindow()
    }
})

渲染进程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>进程通信</title>
</head>
<body>
<h1>进程通信</h1>
<button onclick="sendMessageMain()">发送信息给主进程</button>
</body>
<script>
    const { ipcRenderer } = require('electron');

    //监听
    ipcRenderer.on('send-message-to-render-test', (event, arg) => {
        console.log('渲染进程收到的消息:',arg)
    })
</script>
</html>

image-20210204153232170

原文地址:https://www.cnblogs.com/makalochen/p/14372890.html