0x00 写在前面
在最近的项目中,用到了electron来进行桌面应用的开发。开发过程中涉及到从数据库中获取数据,并在页面中进行渲染这一过程。这一块也是electron开发中很重要的一个知识点:主进程和渲染进程间的通信。
0x01 主进程—ipcMain
ipcMain模块是EventEmitter类的一个实例。 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息。 从渲染器进程发送的消息将被发送到该模块。
1.1 发送消息
- 发送消息时,事件名称为channel。
- 回复同步信息时,需要设置event.returnValue。
- 将异步消息发送回发件人,需要使用event.sender.send(…)。
1.2 方法
IpcMain模块可以使用以下方法来侦听事件:
- ipcMain.on(channel[String], listener[Function])
监听一个事件,当接收到新的消息时 listener 会以 listener(event, args…) 的形式被调用。
- ipcMain.once(channel[String], listener[Function])
这个方法只添加一次性的监听事件,当且仅当下一个消息发送到 channel 时 listener 才会被调用,随后 listener 会被移除。
- ipcMain.removeListener(channel[String], listener[Function])
从监听器数组中移除监听事件(channel)指定的监听器(listener)。
- ipcMain.removeAllListeners([channel][String])
删除所有监听者,或特指的 事件(channel) 的所有监听者.
1.3 事件对象
主进程向callback传递event对象可以有如下方法:
- event.returnValue
在一个同步消息中使用该方法返回值.
- event.sender
在一个异步消息中使用该方法返回值.
0x02 渲染进程—ipcRenderer
ipcRenderer 是一个 EventEmitter 的实例。 可以使用它提供的一些方法从渲染进程 (web 页面) 发送同步或异步的消息到主进程。 也可以接收主进程回复的消息。
2.1 方法
ipcRenderer 模块可以使用以下方法来监听事件和发送消息。
- ipcRenderer.on(channel[String], listener[Function])
监听事件(channel), 当新消息到达,将通过 listener(event, args…) 调用监听器(listener)。
- ipcRenderer.once(channel[String], listener[Function])
为事件添加一个一次性用的监听器(listener) 函数.这个监听器 只有在下次的消息到达 事件(channel) 时被请求调用,之后就被删除了.
- ipcRenderer.removeListener(channel[String], listener[Function])
为特定的事件(channel)从监听队列中删除特定的 listener 监听者.
- ipcRenderer.removeAllListeners(channel[String])
移除所有的监听器,当指定 channel 时只移除与其相关的所有监听器。
- ipcRenderer.send(channel[, arg1][, arg2][, …])
通过事件(channel)发送异步消息到主进程,可以携带任意参数。 在内部,参数会被序列化为 JSON,因此参数对象上的函数和原型链不会被发送。主进程可以使用 ipcMain 监听事件(channel) .
- ipcRenderer.sendSync(channel[, arg1][, arg2][, …])
返回任何由ipcMain处理程序发送过来的值。通过 channel 发送同步消息到主进程,可以携带任意参数。 在内部,参数会被序列化为 JSON,因此参数对象上的函数和原型链不会被发送。主进程可以使用 ipcMain 监听 channel来接收这些消息,并通过 event.returnValue 设置回复消息。
需要注意的是: 发送同步消息将会阻塞整个渲染进程。
0x03 渲染进程—remote
可以使用 remote 模块来调用 main 进程对象的方法,而不必显式发送进程间消息。也就是说,可以使用remote在渲染进程中使用主进程模块。
比如,可以利用下面的代码在渲染进程中新建一个浏览器窗口。
|
|
3.1 远程对象
remote 模块返回的每个对象 (包括函数) 表示主进程中的一个对象 (称之为远程对象或远程函数)。 当调用远程对象的方法时, 调用远程函数, 或者使用远程构造函数 (函数) 创建新对象时, 实际上是在发送同步进程消息。
在上面的渲染进程中新建浏览器窗口时,BrowserWindow和win都是远程对象,new BrowserWindow并不是在渲染进程中创建BrowserWindow对象,而是在主进程中创建了一个BrowserWindow对象,并在渲染进程中返回相应的远程对象,即win对象。
【注意】Electron确保只要渲染进程中的远程对象存在(换句话说,没有被垃圾收集),主进程中的相应对象将不会被释放。也就是说,当远程对象被垃圾回收后,主进程中的相应对象将被接触引用。在这种情况下,如果远程对象在渲染进程中泄露(存储在映射中,但从未释放),则主进程中的相应对象也将被泄露。
3.2 访问主进程中的内置模块
主进程中的内置模块被添加为 remote 模块中的获取器,因此可以像 electron 模块一样直接使用它们。
|
|
3.3 方法
- remote.require(module[String])
返回任何主进程中require(module) 返回的对象。 由其相对路径指定的模块将相对于主进程的入口点来解析。
|
|
|
|
|
|
- remote.getCurrentWindow()
返回 BrowserWindow - 此网页所属的窗口
- remote.getCurrentWebContents()
返回 WebContents - 此网页的 web 内容
- remote.getGlobal(name[String])
返回任何主进程中 name (例如 global[name])的全局变量。
3.4 属性
- remote.process
主进程中的 process 对象。这与 remote.getGlobal(‘process’) 相同, 但已被缓存。
0x04 进程间通信
4.1 同步消息
- 渲染进程
|
|
- 主进程
|
|
4.2 异步消息
- 渲染进程
|
|
- 主进程
|
|
4.3 使用remote通信
|
|
|
|
https://segmentfault.com/a/1190000009253100
4.4 渲染进程间的通信
使用 ipcRenderer.sendTo() 在渲染进程中互相发送通信,更加容易。