02.electron in action(note): chapter03 -主进程与渲染进程

主进程和渲染进程

在electron中,GUI的相关的模块仅在主进程中可用

若渲染进程要完成GUI操作,有两种方式:

  • 渲染进程向主进程发送消息,让主进程完成相应的操作
  • 通过渲染进程的remote模块完成相应的操作

调试主进程

在VSC中,点击左侧的菜单栏的 debug图标,添加launch.json, 添加配置Node.js Electron 主程序

image-20200608170045910

自动生成如下配置:

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        

        {
            "type": "node",
            "request": "launch",
            "name": "Electron Main",
            "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
            "program": "${workspaceFolder}/main.js",
            "skipFiles": [
                "<node_internals>/**"
            ]
        }
        
    ]
}
 在主进程`main.js`中打个断点, 按下快捷键 F5,即可进行调试

调试渲染进程

使用Chrome浏览器的开发者工具, 快捷方式 Ctrl + Shift + I

进程互访

remote

渲染进行访问主进程对象

remote`对象的属性和方法(包括类型的构造函数) 都是主进程的属性和方法的映射。

index.html

      <script>
                require('./index.js')
        </script>

index.js

let { remote } = require('electron');
remote.getCurrentWindow().webContents.openDevTools();

渲染进程访问主进程自定义内容

  • 创建一个Model

    mainModel.js

    let { BrowserWindow } = require('electron')
    exports.makeWin = function () { 
        let win = new BrowserWindow({
            webPreferences: {
                nodeIntegration: true
            }
        });
        return win;
    }
    
  • index.htmlindex.js

    <!DOCTYPE html>
    <html>
    <head>
        <title>窗口标题</title>
    </head>
    <body>
        <h1>Hello World!</h1>
        <div>
            <button id="btn-make-win">创建窗口</button>
        </div>
        <script>
            require('./index.js')
        </script>
    </body>
    </html>
    
    let { remote } = require('electron');
    let mainModel = remote.require('./mainModel');
    
    remote.getCurrentWindow().webContents.openDevTools();
    let win2 = null;
    
    document.getElementById("btn-make-win").addEventListener('click', () => {
        win2 = mainModel.makeWin();
        win2.loadFile('index.html');
    })
    
    

    使用 remote.require加载 mainModel.js', makeWin将在主进程中运行。

    主进程访问渲染进程对象

    因为渲染进程是有主进程创建的,故主进程可以以直接访问渲染进程的对象和类型

进程间消息传递

渲染进程向主进程发送消息

  • index.html
      <button id="btn-ipc-renderer">渲染进程向主进程发送消息</button>
  • index.js

    let { ipcRenderer } = require('electron');
    document.getElementById("btn-ipc-renderer").addEventListener('click', () => {
        ipcRenderer.send('msg_renderer_to_main', { 'param1': "hello" }, { 'param2': "world" });
    })
    

    渲染进程使用 ipcRenderer.send()` 发送消息

  • main.js

    let { ipcMain} = require('electron');
    ...
    app.on('ready', () => {
        ...
        
        ipcMain.on("msg_renderer_to_main", (event, param1, param2) => { 
            console.log(param1);
            console.log(param2);
            console.log(event.sender);
        })
    });
    

    主机进程使用 ipcMain.on接收消息

主进程向渲染进程发送消息

  • main.js

        ipcMain.on("msg_renderer_to_main", (event, param1, param2) => { 
            console.log(param1);
            console.log(param2);
            console.log(event.sender);
            
            //主进程向渲染进程发送消息:方式一
            event.sender.send("msg_main_to_renderer_bysend", { "arg1": "send" }, "msg from main by send!");
            //主进程向渲染进程发送消息:方式二
            event.reply("msg_main_to_renderer_byreply", { "reply-arg1": "reply" }, "msg from main by reply!");
           //主进程向渲染进程发送消息:方式三
            win.send("msg_main_to_renderer_byWindow", { "Window-arg1": "reply" }, "msg from main by Window!");
        })
    
    主线程使用`event.sender.send()`、`event.reply()`、`BrowseWindow.send()` 向渲染进程发送消息,
    

其中 ,event.sender:代表发送消息的渲染进程的webContents

特别注意
无论使用event.sender.send还是event.reply
只有event的发送者所在的渲染进程才收到消息, 如果使用win.send(),那么 只用win所在的在渲染进程才能收到消息

  • index.js
ipcRenderer.on('msg_main_to_renderer_bysend', (event, param1, param2) => {
    console.log(param1);
    console.log(param2);
});

ipcRenderer.on('msg_main_to_renderer_byreply', (event, param1, param2) => {
    console.log(param1);
    console.log(param2);
});

ipcRenderer.on('msg_main_to_renderer_byWindow', (event, param1, param2) => {
    console.log(param1);
    console.log(param2);
});

渲染进程使用ipcRenderer.on()接收主线程的消息

渲染进程间消息传递

通过主进程中转

        窗口之间传递的消息,都先发到主进程,再由主进程转发

通过窗口的webContents.id

  • index.html

        <button id="btn-send-msg-between-renderer">渲染进程间发送消息</button>
    
  • index.js

    let win2 = null;
    document.getElementById("btn-make-win").addEventListener('click', () => {
        win2 = mainModel.makeWin();
        win2.loadFile('index.html');
    })
    ...
    
    //渲染进程间直接发送消息
    document.getElementById("btn-send-msg-between-renderer").addEventListener('click', () => {
        console.log("msg_between_renderer");
        ipcRenderer.sendTo(win2.webContents.id, 'msg_renderer_to_renderer', { 'param1': "hello" }, { 'param2': "world" });
    });
    //接收渲染进程间消息
    ipcRenderer.on('msg_renderer_to_renderer', (event, param1, param2) => {
        console.log(param1);
        console.log(param2);
    });
    

Remote模块的局限性

  • 性能消耗大

  • 制造混乱

  • 制造假象

  • 存在安全问题

posted @ 2020-06-09 21:32  easy5  阅读(267)  评论(0编辑  收藏  举报