我在Angular 7.1.1和Electron 4.1.4项目中遇到了一个奇怪的问题。
数据流:
问题: 当数据到达我的write-docx函数时,它缺少导出过程必不可少的对象子数组。
在将数据发送到docx-templater.service之前,以及在该服务将其发送到ipcRenderer之前(我的数据服务),我已经验证了该数据在电子的Chrome开发人员工具控制台中是否完美和报表生成器功能正在按设计工作)。当我通过将数据保存到JSON文件中来检查main.ts中的数据时,它仅缺少JSON的第二个对象内的controls子数组。控件子数组按预期显示在第一个对象中。
我将注意到ipcMain函数产生的是一个格式正确的JSON文件,因此它实际上只是排除了“ controls”子数组,并且不会由于内存或缓冲区限制或类似原因而被截断。
report-builder.component.ts
createReport() {
if (this.reportBuilderFG.get('allControls').value) {
this.db.fnGetCompleteControlList()
.then((groups: Group[]) => {
this.word.createCompleteDocument(groups, this.reportBuilderFG.get('folder').value + '\\filename.docx')
.then(() => {
this.openSnackBar(this.reportBuilderFG.get('folder').value + '\\filename.docx created successfully');
});
});
} else {
// Do other stuff
}
docx-templater.service.ts
createCompleteDocument(data, folder: string): Promise<boolean> {
return new Promise(resolve => {
console.log(data) <=== Data is perfect here.
ipcRenderer.send('writeCompleteDocument', {data: data, folder: folder});
resolve();
});
}
main.ts
import { writeCompleteDocument } from './node_scripts/write-docx';
ipcMain.on('writeCompleteDocument', (event, arg) => {
fs.writeFileSync("IPCdata.json", arg.data); // <==== Part of the data is missing here.
writeCompleteDocument(arg.data, arg.folder);
});
Good Data Example (some keys and objects excluded for brevity)
[
{
"name": "General Security",
"order": 1,
"subgroups": [
{
"_id": "GOV",
"name": "Governance",
"order": 1,
"controls": [
{
"group": "GS",
"subgroup": "GOV",
"active": true,
"printOrder": 1,
"name": "This is my GS control name",
"requirements": [
{
"id": "SA01",
"active": true,
"order": 1,
"type": "SA",
"applicability": [
"ABC",
"DEF",
"GHI"
],
},
{ ... 3 more }
],
"_id": "GSRA-03",
"_rev": "1-0cbdefc93e56683bc98bae3a122f9783"
},
{ ... 3 more }
],
"_id": "GS",
"_rev": "1-b94d1651589eefd5ef0a52360dac6f9d"
},
{
"order": 2,
"name": "IT Security",
"subgroups": [
{
"_id": "PLCY",
"order": 1,
"name": "Policies",
"controls": [ <==== This entire sub array is missing when exporting from IPC Main
{
"group": "IT",
"subgroup": "PLCY",
"active": true,
"printOrder": 1,
"name": "This is my IT control name",
"requirements": [
{
"id": "SA01",
"active": true,
"order": 1,
"type": "SA",
"applicability": [
"ABC",
"DEF",
"GHI"
],
}
],
"_id": "GSRA-03",
"_rev": "1-0cbdefc93e56683bc98bae3a122f9783"
}
}
],
"_id": "IT",
"_rev": "2-e6ff53456e85b45d9bafd791652a945c"
}
]
我希望ipcRenderer完全将JSON传递给ipcMain.on函数,但是不知何故,它会修剪部分数据。在将数据发送到渲染器之前,我什至尝试对数据进行分层处理,然后在另一侧对其进行解析,但这无济于事。
这可能是异步的吗?我不知道下一步该去哪里调试,并且发现我在此过程中犯了什么白痴错误。
此外,我意识到上述数据流对于我正在做的事情来说似乎过于复杂,并且我可能可以更轻松地完成此工作,但这对于整个应用程序的结构方式来说是有道理的,因此我将如果我能解决这个问题,那就去吧。
答案 0 :(得分:0)
我能够通过在Report-builder.component.ts中的fnGetCompleteControlList()数据提取之后添加1000毫秒的超时来解决此问题。似乎我还有很多工作要学习异步功能。 :-(
report-builder.component.ts
createReport() {
if (this.reportBuilderFG.get('allControls').value) {
this.db.fnGetCompleteControlList()
.then((groups: Group[]) => {
setTimeout(() => {
this.word.createCompleteDocument(groups, this.reportBuilderFG.get('folder').value + '\\filename.docx')
.then(() => {
this.openSnackBar(this.reportBuilderFG.get('folder').value + '\\filename.docx created successfully');
});
}, 1000);
});
} else {
// Do other stuff
}
答案 1 :(得分:0)
好像您的createCompleteDocument()
函数设置不正确。快速搜索显示ipcRenderer
是一个异步函数,但是您(几乎)同步对其进行响应。
您有以下内容,(可能)是不正确的(实际上绝对是不正确的,因为您在Promise<boolean>
处键入了Promise<void>
的返回值):
createCompleteDocument(data, folder: string): Promise<boolean> {
return new Promise(resolve => {
ipcRenderer.send('writeCompleteDocument', {data: data, folder: folder});
resolve();
});
}
ipcRenderer#send()
是异步的,但是您随后立即调用resolve()
,而无需等待函数解析。这可能可以解释为什么添加setTimeout()
可以为您解决问题。查看ipcRenderer
docs,以下内容可能会满足您的要求:
createCompleteDocument(data, folder: string): Promise<Event> {
return new Promise(resolve => {
ipcRenderer.once('writeCompleteDocument', resolve);
ipcRenderer.send('writeCompleteDocument', {data: data, folder: folder});
});
}
好像回调函数传递了一个Event object。
另一种选择是在原始代码中简单地将ipcRenderer#send()
替换为ipcRenderer#sendSync()
,但是该方法的文档中指出了这一点:
发送同步消息将阻止整个渲染器进程,除非您知道自己在做什么,否则永远不要使用它。
几乎肯定要使用ipcRenderer#send()
和ipcRenderer#once()
。
您可以分别切换到async/await functions来清理代码。例如:
async createReport(): Promise<void> {
if (this.reportBuilderFG.get('allControls').value) {
const groups: Group[] = await this.db.fnGetCompleteControlList();
await this.word.createCompleteDocument(
groups,
this.reportBuilderFG.get('folder').value + '\\filename.docx'
);
// Unclear if this function is actually async
await this.openSnackBar(
this.reportBuilderFG.get('folder').value +
'\\filename.docx created successfully'
);
} else {
// Do other stuff
}
}