electron 电子IPC消息被多次记住和重新调用

vuktfyat  于 2023-11-15  发布在  Electron
关注(0)|答案(1)|浏览(353)

我有一个Electron应用程序,它有多个按钮可以生成文档。这些文档实际上只是HTML页面,它们被加载到一个新的BrowserWindow中,并通过IPC接收自定义参数,然后通过JavaScript注入文档。
对于通过IPC传递参数,我使用了一个我称为'document-params'的通道。所有文档都使用这个通道。我的期望是发送到通道的消息将被其侦听器消耗,并从Electron正在使用的任何IPC队列中消失。相反,就好像发送到该通道的所有消息都保留在通道中一样。每个新的文档调用都会接收通道中所有以前的消息,沿着。如果我多次调用同一个文档,它的数据会多次插入到文档中。如果我调用不同的文档,我可以看到前一个文档的注入函数无法在当前文档下运行(调用document.getElementById())失败。
据我所知,我遵循Electron IPC教程。我在文档中没有看到任何地方提到消息保留在IPC通道中,这无论如何都是违反直觉的行为。
下面是我的代码是如何设置的:
我有两个文档,每个文档在package.json中定义为自己的入口点:

{
    "name": "document_contract",
    "html": "./src/renderer/windows/documents/Contract.html",
    "js": "./src/renderer/windows/documents/renderer.js",
    "preload": {
        "js": "./src/renderer/windows/documents/preload.js"
    }
},
{
    "name": "document_review_draft",
    "html": "./src/renderer/windows/documents/ReviewDraft.html",
    "js": "./src/renderer/windows/documents/renderer.js",
    "preload": {
        "js": "./src/renderer/windows/documents/preload.js"
    }
}

字符串
下面是renderer.js和preload.js文件

/src/renderer/windows/documents/preload.js

const { contextBridge } = require('electron');
import { preloadCommon } from '../preload.js';

contextBridge.exposeInMainWorld('electronAPI', {...preloadCommon});

../preload.js

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

export const preloadCommon = {
    subscribe: (channel, callback) => {
        ipcRenderer.on(channel, callback);
    },
    getPopupParams: () => {
        ipcRenderer.send('popup-params');
    },
    getDocumentParams: () => {
        ipcRenderer.send('document-params');
    },
    popup: (name, data) => {
        ipcRenderer.send('popup', name, data);
    },
    generateDocument: (template, title, data) => {
        ipcRenderer.send('document', template, title, data);
    }
};

/src/renderer/windows/documents/renderer.js

import '../renderer.js';

function bootstrapContract(data) {
    // Document appropriate DOM manipulation, such as injecting <li> elements from data
}

function bootstrapReviewDraft(data) {
    // Document appropriate DOM manipulation, such as injecting <li> elements from data
}

function dispatch(template, data) {
    switch (template) {
        case 'contract':
            bootstrapContract(data);
            break;
        case 'review-draft':
            bootstrapReviewDraft(data);
            break;
        default:
            break;
    }
}

window.electronAPI.subscribe('document-params', (event, template, data) => dispatch(template, data));
window.electronAPI.getDocumentParams();


在主进程中,以下是如何处理通道的:

const { ipcMain, BrowserWindow } = require("electron");
const path = require('path');

let popup;

const templates = {
    'contract': DOCUMENT_CONTRACT_WEBPACK_ENTRY,
    'review-draft': DOCUMENT_REVIEW_DRAFT_WEBPACK_ENTRY,
};

const createDocument = (template, title, data) => {
    popup = new BrowserWindow({
        show: true,
        webPreferences: {
            preload: DOCUMENT_CONTRACT_PRELOAD_WEBPACK_ENTRY
        },
        title: title,
        parent: global.mainWindow,
        modal: true,
    });
    popup.loadURL(templates[template]);
    popup.maximize();
    popup.show();
};

ipcMain.on('document', (event, template, title, data) => {
    const onPassParamsToDocument = (event) => {
        event.sender.send('document-params', template, data);
    };
    ipcMain.on('document-params', onPassParamsToDocument);
    createDocument(template, title, data);
});

0yg35tkg

0yg35tkg1#

在main上,每次在"document"通道上收到消息时,都会为"document-params"创建一个新的侦听器。由于从未删除这些侦听器,因此可以肯定这会导致问题。
IPC侦听器可以使用ipcMain.removeListener()ipcMain.removeAllListeners()删除。
你的实现似乎也过于复杂,当你调用main并期望响应时,你可能应该考虑使用invoke/handle而不是send/on

相关问题