本文作者:IMWeb laynechen

未经同意,禁止转载

Electron 中的进程分类

在 Electron 中,存在两种进程:主进程和渲染进程。

主进程 (Main Process)

一个 Electron 应用只有 一个主进程

当我们执行 electron . 命令后, Electron 会运行当前目录(.)下的 package.json 文件中 main 字段指定的文件。而运行该文件的进程既是主进程。

运行在主进程中的脚本可以通过创建一个窗口,并传入 URL,让这个窗口加载一个网页来展示图形界面。

与创建 GUI 相关的接口只应该由主进程来调用。

渲染进程 (Renderer Process)

在Electron里的每个页面都有它自己的进程,叫作渲染进程。主进程通过实例化 BrowserWindow,每个 BrowserWindow 实例都在它自己的渲染进程内返回一个 web 页面。当 BrowserWindow 实例销毁时,相应的渲染进程也会终止。

渲染进程由主进程进行管理。每个渲染进程都是相互独立的,它们只关心自己所运行的 web 页面。

问题

这篇文章主要要解决的问题是:

Electron 与 View 层(网页),也就是主进程与渲染进程是如何进行通信的?

不同的通信是如何实现的?

先解决第一个问题。

Electron 与 View 层(网页)是如何进行通信的?

Electron 提供了两种通信方法:

1. 利用 ipcMain 和 ipcRenderer 模块

官方文档 上有使用这两个模块进行进程通信的例子:

// In main process.

const {ipcMain} = require('electron')

ipcMain.on('asynchronous-message', (event, arg) => {

console.log(arg) // prints "ping"

event.sender.send('asynchronous-reply', 'pong')

})

ipcMain.on('synchronous-message', (event, arg) => {

console.log(arg) // prints "ping"

event.returnValue = 'pong'

})

// In renderer process (web page).

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')

渲染进程可以通过 ipcRenderer 模块的 send 方法向主进程发送消息。在主进程中,通过 ipcMain 模块设置监听 asynchronous-message 和 synchronous-message 两个事件,当渲染进程发送时就可以针对不同的事件进行处理。

主进程监听事件的回调函数中,会传递 event 对象及 arg 对象。arg 对象中保存渲染进程传递过来的参数。通过 event.sender 对象,主进程可以向渲染进程发送消息。如果主进程执行的是同步方法,还可以通过设置 event.returnValue 来返回信息。

上面说了渲染进程如何向主进程发送消息,但主进程也可以主动向渲染进程发送消息

在主进程中,我们会创建一个 BrowserWindow 对象,这个对象有 webContents 属性。webContets 提供了 send 方法来实现向渲染进程发送消息。当然 webContents 对象远不止这两个通信方法,具体可以看 webContents

下面是官方文档提供的使用 webContents 实现通信的例子:

// In the main process.

const {app, BrowserWindow} = require('electron')

let win = null

app.on('ready', () => {

win = new BrowserWindow({width: 800, height: 600})

win.loadURL(`file://${__dirname}/index.html`)

win.webContents.on('did-finish-load', () => {

win.webContents.send('ping', 'whoooooooh!')

})

})

console.log(message) // Prints 'whoooooooh!'

})

注意,webContents.on 监听的是已经定义好的事件,如上面的 did-finish-load。要监听自定义的事件还是通过 ipcMain 和 ipcRenderer。

渲染进程的监听事件回调函数中,也可以通过 event.sender 来向主进程发送消息。这个对象只是 ipcRenderer 的引用(event.sender === ipcRenderer)。因此,event.sender 发送的消息在主进程中还是需要通过 ipcMain.on 方法来监听,而不是通过 webContents.on 方法。

2. 利用 electron.remote 模块

在渲染进程中,可以通过

const { remote } = require('electron');

获取到 remote 对象,通过 remote 对象可以让渲染进程访问/使用主进程的模块。例如,通过 remote 在渲染进程中新建一个窗口:

const {BrowserWindow} = require('electron').remote

let win = new BrowserWindow({width: 800, height: 600})

win.loadURL('https://github.com')

同样的,我们也可以通过 remote 对象访问到 app 对象。这样我们就可以访问到我们在主进程中挂载到 electron.app 对象上的方法。

如:

main.js 文件:

// In main process

const { app } = require('electron');

const utils = require('./utils');

app.utils = utils; // 将在 Electron 层实现的接口绑定到 app 上

index.js 文件(被网页引用的脚本文件):

const { remote } = require('electron');

// In renderer process

function(){

// remote.app.utils 对象与上述文件中的 utils 对象是一样的。

remote.app.utils.test();

}

Electron 的两种进程通信方法是如何实现的?

知道怎么用还不够,还需要了解 Electron 是如何实现这两种通信方法的,以及 Electron 为什么要实现两种通信方法,这两种通信方法的有什么不同的地方。弄清楚这些开发起来才会对程序的数据流比较清晰。

ipcMain 和 ipcRenderer

The ipcMain module is an instance of the EventEmitter class. When used in the main process, it handles asynchronous and synchronous messages sent from a renderer process (web page). Messages sent from a renderer will be emitted to this module.

ipcMain 和 ipcRenderer 都是 EventEmitter 类的一个实例。而 EventEmitter 类由 NodeJS 中的 events 模块导出。

events.EventEmitter

EventEmitter 类是 NodeJS 事件的基础,实现了事件模型需要的接口, 包括 addListener,removeListener, emit 及其它工具方法. 同原生 JavaScript 事件类似, 采用了发布/订阅(观察者)的方式, 使用内部 _events 列表来记录注册的事件处理器。

我们通过 ipcMain和ipcRenderer 的 on、send 进行监听和发送消息都是 EventEmitter 定义的相关接口。

那么 ipcMain 和 ipcRenderer 是如何实现这些接口的呢?

ipc-renderer.js

const binding = process.atomBinding('ipc')

...

// Created by init.js.

const ipcRenderer = v8Util.getHiddenValue(global, 'ipc')

ipcRenderer.send = function (...args){

return binding.send('ipc-message', args)

}

....

module.exports = ipcRenderer

调用了 atomBinding('ipc') 得到的 binding 对象的 send 方法。能力有限,就分析到这。后面 binding.send 应该就是 IPC 相关的实现了:对传送的数据进行序列化和反序列化。

// 主进程

ipcMain.on('test1', (e) => {

const obj = {};

obj.toJSON = () => 'call toJSON';

e.returnValue = obj;

})

ipcMain.on('test2', (e) => {

const obj = { name: '123' };

e.returnValue = obj;

})

// 渲染进程

let returnValue = ipcRenderer.sendSync('test1');

console.log(typeof returnValue, returnValue); // 'string call toJSON'

returnValue = ipcRenderer.sendSync('test2');

console.log(typeof returnValue, returnValue); // 'object Object name: "123"__proto__: Object'

从渲染进程输出的消息可以看到,主进程将返回值调用 toJSON 后传递给渲染进程。渲染进程再对传输过来的内容进行反序列化。

remote 远程对象

通过 remote 对象,我们可以不必发送进程间消息来进行通信。但实际上,我们在调用远程对象的方法、函数或者通过远程构造函数创建一个新的对象,实际上都是在发送一个同步的进程间消息(官方文档 上说这类似于 JAVA 中的 RMI)。

也就是说,remote 方法只是不用让我们显式的写发送进程间的消息的方法而已。在上面通过 remote 模块创建 BrowserWindow 的例子里。我们在渲染进程中创建的 BrowserWindow 对象其实并不在我们的渲染进程中,它只是让主进程创建了一个 BrowserWindow 对象,并返回了这个相对应的远程对象给了渲染进程。

参考资料

electron监听网页_Electron 进程通信相关推荐

  1. chrome扩展(插件)开发(五)监听网页的ajax请求

    我的插件想要监听网页发出的请求, 然后根据请求的状态来做具体的操作. 实现的方法主要有三种方式 google官方提供的api chrome.webRequest 这里在插件中监听宿主页面的ajax 重 ...

  2. 通过Webkit远程调试协议监听网页崩溃

    背景介绍 因为正在开发一个项目,而这个项目使用到了puppeteer,其中有个功能是在puppeteer打开的chrome里打开多个Tab,并进行管理. 虽然puppeteer可以打开多个网站,但是并 ...

  3. 我偷偷监听了他们的通信流量......

    ‍‍ 作者 | 轩辕之风 来源 | 编程技术宇宙(ID:xuanyuancoding) 我是一个监听软件,主人花了好几个晚上才把我开发出来,我的使命是监听网络中的所有流量然后报告给他. 那天,主人给要 ...

  4. php监听网页日志,如何用php程序监听一个不断增长的日志文件

    首先这个日志文件写入不是很频繁,它每一行就是一条有效的日志.我想php程序来监听这个文件,每当被写入一行的时候,我的php就自动读入一行,做出分析然后做相应的处理.请问要如何实现呢? 回复内容: 首先 ...

  5. WebView监听网页加载成功与失败

    问题说明: 现在好多APP在应用中会内嵌webview,好多时候需要监听webview是否加载成功与失败.当加载成功的时候会回调WebViewClient的onPageFinished方法:当加载失败 ...

  6. 1.1.14 Electron 监听网络状态

    可以用window.addEventListener来进行时间监听网络状态 JavaScript的一种方式进行监听网络状态,监听的事件分别是online和offline. online : 如果链接上 ...

  7. 监听网页微信扫码支付成功_网付扫码点餐新福利,消费者点餐可获微信支付金币奖励...

    扫码点餐相信大家都不陌生,即能餐饮解决商家人力物力投入成本痛点,又能方便消费者点餐.现今已成为了餐饮商户的标配系统.近两年,很多系统厂商都在试水扫码点餐领域.尤其是聚合支付服务商,拥有得天独厚的优势. ...

  8. 监听网页微信扫码支付成功_PC网页微信扫码支付(模式二)

    WeixinWebUtil(微信请求工具类) public class WeixinWebUtil { private static Logger log = LoggerFactory.getLog ...

  9. 云闪付APP内嵌H5监听左上角X关闭事件

    最近在做云闪付蓝牙对接,遇到的一个问题. 需求 用户进入云闪付APP内嵌 H5页面调用接口连上蓝牙后,可能不想支付使用,或其他原因,随手关闭左上角X关闭浏览器,这时需要监听这个动作,断开蓝牙连接,不然 ...

最新文章

  1. 10个人围成一圈循环报数,输出最后出圈的人
  2. 报错笔记:cannot convert parameter 1 from 'char [1024]' to 'unsigned char *'
  3. INT(M)表示什么意思?
  4. spring指导的index.html在spring文件夹中的位置
  5. 如何在VSTFS中设置email notification
  6. 函数传参之商品价格计算—JS学习笔记2015-6-6(第50天)
  7. 国外一教授坦言,用这方法能迅速成为python程序员,但都不愿意说
  8. vue cli3--创建通用模版
  9. tensorflow 中MNIST数据集下载
  10. 《手把手教你学DSP》总结1
  11. windows 即时贴_如何在Windows 10上使用即时贴
  12. 百度搜索引擎的工作原理
  13. Ubuntu18.0.4深度学习环境搭建及相应软件安装(Update)
  14. Android多媒体框架一
  15. IIS8/IIS7/IIS6 出现ADODB.Connection 错误 '800a0e7a'的解决办法
  16. Linux 基础知识总结
  17. 数字IC后端知识扫盲——OCV(上)
  18. 三菱FX系列PLC以太网通讯
  19. Golang panic:WaitGroup is reused before previous Wait has returned
  20. RED5的API介紹-4

热门文章

  1. 海康威视监控有意思的问题
  2. 孟子曰:吾善养吾浩然之气
  3. Archlinux 虚拟机 virtualbox-ose
  4. 全球与中国超高纯度热交换器市场深度研究分析报告
  5. 地震勘探基础(十)之地震速度关系
  6. [转载]ME51n,ME52n,ME53n屏幕增强
  7. 构造函数和析构函数的作用是什么?什么时候需要自己定义构造函数和析构函数?
  8. 润滑油市场现状研究分析与发展前景预测报告
  9. IDEA修改project name和modules name(亲测有效)
  10. Beta阶段团队项目开发篇章1