是否可以将 ipcRenderer 收到的消息保存在电子中,以便在 ipcRenderer 范围之外使用?

Posted

技术标签:

【中文标题】是否可以将 ipcRenderer 收到的消息保存在电子中,以便在 ipcRenderer 范围之外使用?【英文标题】:Is it possible to save message received by ipcRenderer in electron to be used outside of the scope of the ipcRenderer? 【发布时间】:2021-08-14 19:54:33 【问题描述】:

这是我拥有的代码的准系统。想知道是否有人知道比我“尝试”做的更好的方法......我认为我遇到了麻烦,因为我在块、函数和全局范围方面的经验很少,但是我觉得我已经尝试了 let 的每一种组合, var, const 等...

任何帮助将不胜感激。

P.s 这个脚本在我的应用程序的前端运行。该消息是从一个名为 background.js 的文件发送的,并在 electron 启动从我的操作系统收集数据的应用程序时运行

<script>
    
    const ipcRend = require('electron').ipcRenderer
    var savedData = null
    
    ipcRend.on('channel', (event, data) => 
    savedData = data
    console.log(data) // outputs as expected
    console.log(savedData) // outputs as expected
    )

    console.log(savedData)// undefined
    
    </script>

【问题讨论】:

在从主进程接收到事件之前调用最后一个 console.log()。目前尚不清楚您到底想做什么。 【参考方案1】:

您遇到的问题不仅与范围有关,还与代码流有关。这是执行命令的顺序。在您的情况下,console.log(savedData) 在您的侦听器设置变量之前执行。

为什么?因为您的代码不会等到它收到"channel" 事件。仅执行ipcRenderer.on (event, callback); 注册 callback 函数与ipcRenderer。每当收到event 时,就会执行callback。本质上,您可以将其视为一个函数,只需将callback 存储在一个内部变量中,只要设置了值就会返回。

这是异步编程的核心概念:向事件处理程序注册回调以便能够并行运行代码(在您的情况下,callback 将在其他代码空闲时执行)。如果我要说明您案例中的代码流程,我会这样做:

const ipcRend = require('electron').ipcRenderer  // (1)
var savedData = null                             // (2)

ipcRend.on(                                      // (3)
    'channel',
    (event, data) =>                            // (5)
        savedData = data
        console.log(data)
        console.log(savedData)
    
)

console.log(savedData)                           // (4)

首先,执行您的变量声明 (1) 和 (2)。然后,(3),ipcRend.on(...) 紧随其后。这里有一个问题:下一个正在执行的代码是 (4),使用 null 变量 savedData 调用 console.log ();。您的匿名回调函数(大括号内带有(event, data) =&gt; 的内容)(5) 仅在收到事件"channel" 后执行。这可能随时发生,但很可能不会在您使用 ipcRenderer 注册此回调时发生。

因此,如果您想在执行任何其他代码之前等待回调运行,则可以使用 Promise(在 MDN 上阅读有关 Promises 的更多信息):

const ipcRend = require('electron').ipcRenderer
var savedData = null

await new Promise ((reject, resolve) => 
    ipcRend.on(
        'channel',
        (event, data) => 
            savedData = data
            console.log(data)
            console.log(savedData)
            resolve ();
        
    )
);

console.log(savedData)

这样console.log (savedData);只会在回调函数运行后执行。

但是,这不仅笨拙,而且也不完全是最佳实践。由于您已经在处理异步编程,因此最好调用另一个函数,将您收到的数据作为参数,而不是将其存储在全局范围内。这种方式更容易理解,也更容易长时间维护:

function processReceivedData (data) 
    console.log (data);
    // Anything else you want to do with this data...


const  ipcRenderer  = require ("electron");

ipcRenderer.on ("channel", (event, data) =>  processData (data); );

看到了吗?更干净,更易于理解,并且没有更多的全局变量!当然,有时只需要全局变量。但是要确保没有同步代码依赖于变量值,这些变量值只会在任何异步事件发生后设置。


作为脚注:在导入的声明中使用,就像我上面使用的那样,会自动将加载的模块“解包”到所需的变量中。这样一来,你就必须在你想使用它的时候写ipcRenderer(我知道这更长),但是使用这种方法不太容易出错,因为你不必写require().&lt;submodule you actually want&gt;。此外,您可以一次解压缩多个子模块:const ipcRenderer, contextBridge = require ("electron"); 一次加载两个模块并将它们存储在ipcRenderercontextBridge 中。

【讨论】:

以上是关于是否可以将 ipcRenderer 收到的消息保存在电子中,以便在 ipcRenderer 范围之外使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何在反应中导入 ipcRenderer?

ipcRenderer 发送与 sendSync

如何使用ipcRenderer发送多个参数

preload.ts 中的 contextBridge.exposeInMainWorld:ipcRenderer 接收到来自 main.ts 的消息但渲染器没有得到它

将画布保存为 png:是不是可以在 Chrome 中删除 MIME 类型的警告消息?

07.electron-(渲染进程和主进程)通信