electron框架学习之浅析IPC使用

来源:互联网 发布:java业余培训 编辑:程序博客网 时间:2024/06/06 07:33

一、先介绍一下webContents:

webContents负责渲染和控制一个web页面,它是Browserwindow对象的一个属性。利用它可以做以下的事情,可以emit出很多事件像是完成装载,login等和主web页面相关的一些事件。另外几个比较重要的函数是
1)webContents.loadURL(url[,options])
往窗口中装载url,必须以如下格式:http://或是file://
2)webContents.downloadURL(url)
在URL中初始化一个下载的资源
3)webContents.getURL()
获取当前页面的URL
4)webContents.getTitle()
5)webContents.isLoading()
6)webContents.isWaitingForResponse()
7)webContents.stop()
8)webContents.reload()
9)webContents.reloadIgnoringCache()
10)webContents.canGoBack()
11)webContents.canGoForward()
12)webContents.CanGoToOffser(offset)
13)webContents.clearHistory()
14)webContents.goBack()
15)webContents.goForward()
16)webContents.goToIndex(index)
17)webContents.goToOffset(offset)
18)webContents.isCrashed()
19)webContents.setUserAgent(userAgent)
20)webContents.getUserAgent()
21)webContents.insertCSS(css)
22)webContents.executeJavaScript(code[,userGesture, callback])
23)webContents.setAudioMuted(muted)
24)webContents.isAudioMuted()
25)webContents.undo()
26)webContents.redo()
27)webContents.cut()
28)webContents.copy()
29)webContents.paste()
30)webContents.pasteAndMatchStyle()
31)webContents.delete()
32)webContents.selectAll()
33)webContents.unselect()
34)webContents.replace(text)
35)webContents.replaceMisspelling(text)
36)webContents.insertText(text)
37)webContents.findInPage(text[,options])

...
重点介绍webContents.send(channel[, arg1][, arg2][,...])
发送一个异步消息给渲染进程,也可以发送任意的参数。可以利用ipcRenderer模块来监听channel中的消息。例如:

var window = null;
app.on('ready', function(){
    window = new BrowserWindow({width: 800, height: 600});
    window.loadURL('file://'+__dirname+'/index.html');
    window.webContents.on('did-finish-load', function(){
        window.webContents.send('ping', 'whooooooooooo');
        });
    
    });
    
    <html>
        <body>
            <script>
                require('electron').ipcRenderer.on('ping', function(event, message){
                    console.log(message);
                    });
                </script>
        </body>
    </html>

二、再认识下ipcMain模块

ipcMain模块是EventEmitter类的实例,当在主进程中使用的时候,它处理了渲染进程中发过来的同步和异步消息。从渲染进程中发送过来的消息会被emit到这个模块中。同样可以利用webContents.send来发送消息给ipcRenderer,发送异步消息的话,使用的是event.returnValue,发送的是同步消息的话,使用的是event.sender.send(...)
//in main process
const ipcMain = require('electron').ipcMain;
ipcMain.on('asynchronous-message', function(event, arg){
    event.sender.send('asynchronous-reply', 'pong');
    });
ipcMain.on('synchronous-message', function(event, arg){
    event.returnValue = 'pong';
    });
//In renderer process(web page)
const ipcRenderer = require('electron').ipcRenderer;
ipcRenderer.on('asynchronous-reply', function(event, arg) {
    
    });
ipcRenderer.send('asynchronous-message', 'ping');

//以上部分是Main Process中的模块
//下面介绍下Rendering Process中的模块

三、先说说ipcRenderer

ipcRenderer模块是EventEmitter的实例,提供了一些函数发送同步和异步的消息给主进程。
ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])
类似ipcRenderer.send但是事件会被发送到<webview>元素中而不是主进程中
下面说说remote
remote模块提供了一个简单的IPC通信方式来实现渲染进程和主进程之间的信息交互。
在electron中GUI相关的模块只能是在主进程中使用,而不是渲染进程。为了在渲染进程中使用,ipc模块必须发送跨进程消息给主进程。通过remote模块,可以调用相应的函数而不需要通过发送显式的消息。类似于Java和RMI,下面是一个在渲染进程中创建一个浏览器窗口的例子:
const remote = require('electron').remote;
const BrowserWindow = remote.BrowserWindow;

var win = new BrowserWindow({ width: 800, height: 600});
win.loadURL('https://github.com');

反过来在主进程中执行渲染进程中的javascript可以通过webContents.executeJavaScript

四、关于Remote对象

每个由remote返回的对象包含函数,都代表的是主进程中的对象。当通过remote对象调用一个remote函数或是创建一个新的对象的时候,实际上就是发送了一个异步的跨进程消息。
在上面的例子中,BrowserWindow和win都是remote对象,在渲染进程中是没法通过new BrowserWindow创建主窗口的。但是却可以通过remote对象在主进程中创建对应的窗口然后返回给win对象。
但是只有enumerable properties可以通过remote对象访问。关于enumerable properties请看:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties;
Remote对象的声明周期
electron保证只要remote对象还在渲染进程中存在那么在主进程中对应的对象就不会被释放。当remote对象被垃圾回收了,在主进程中对应的对象才会被释放。
如果remote对象在渲染进程中泄露比如存储在一个map对象中从不释放,那么在主进程中对应的对象也会产生泄露的情况,所以必须小心使用。
往主进程中传递回调函数
在主进程中的代码可以接收从渲染进程中传递过来的回调函数,比如remote模块,但是必须非常的小心使用。
首先,为了避免死锁,传递给主进程的回调函数必须是异步调用的,主进程是不可能获取到传递过来的回调函数的返回值的。
比如你不能使用在主进程中调用的来自渲染进程的Array.map:

//in main process mapNumbers.js
exports.withRedererCallback = function(mapper){
    return [1,2,3].map(mapper);
    };
exports.withLocalCallback = function(){
    return exports.mapNumbers(function(){
        return x + 1;});
    };
//renderer process
var mapNumbers = require('remote').require("./mapNumbers");

var widtheRendererCb = mapNumbers.withRendererCallback(function(x){
    return x + 1;
    });
var withLocalCb = mapNumbers.withLocalCallback();

正如所见,渲染进程中的回调函数的返回值是获取不到的。其次,传递给主进程的回调函数会保留到主进程被回收为止。
除非显示uninstall,不然callback会一直被主进程引用。如果没有主动uninstall,那么每次reload界面的时候callback又会被重新install一次,每次启动都会泄露callback。
而且更为糟糕的是,由于先前install的callback的context对象已经被释放,所以当主进程发出一个close事件的时候会出现异常。
为了避免这样的问题的发生,要确保清理干净从渲染进程传递给主进程的任何引用,这包含了清理event handler,或者保证主进程显式的解引用这些callbacks
访问主进程中的内建模块
主进程中的内建模块可以通过remote模块的getters来获取,比如:

const  app = remote.app;

以上仅是记录以备忘,后面会结合实际项目,将electron,nodejs配合用typescript更改模块引入方式,以及利用nodejs的package模式灵活加载项目中不同功能的模块。

1 0