是否可以将 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) =>
的内容)(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().<submodule you actually want>
。此外,您可以一次解压缩多个子模块:const ipcRenderer, contextBridge = require ("electron");
一次加载两个模块并将它们存储在ipcRenderer
和contextBridge
中。
【讨论】:
以上是关于是否可以将 ipcRenderer 收到的消息保存在电子中,以便在 ipcRenderer 范围之外使用?的主要内容,如果未能解决你的问题,请参考以下文章
preload.ts 中的 contextBridge.exposeInMainWorld:ipcRenderer 接收到来自 main.ts 的消息但渲染器没有得到它