Electron contextBridge returns undefined



我有这4个项目文件:

main.js
preload.js
renderer.js
index.html

节点:17.4.0电子:18.2.0

我试图在我的文件系统上打开一个文本文件,由renderer.js中的单击事件触发-然后将文本文件的内容加载到index.html中的<div>标签中。

main.js

const {app, BrowserWindow, ipcMain} = require("electron");
const path = require("path");
const fs = require("fs");
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
}
});
mainWindow.loadFile(path.join(__dirname, "index.html"));
// Open the DevTools.
mainWindow.webContents.openDevTools();
};
app.on("ready", () => {
createWindow();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});

function openFile(){
fs.readFile("logs.txt", "utf8", (err, data) => {
if (err) {
console.error(err);
return "Error Loading Log File";
}
console.log(data);
return data;
});
}
ipcMain.handle("channel-load-file", openFile);

preload.js

const {contextBridge, ipcRenderer} = require("electron");
contextBridge.exposeInMainWorld("electronAPI", {
loadFile: () => ipcRenderer.invoke("channel-load-file")
});

renderer.js

const btn = document.querySelector("#btn");
btn.addEventListener("click", e => {
let data = window.electronAPI.loadFile();
document.getElementById("main-content").innerText = data;
});

我可以肯定地看到console.log(data);中的日志文件的内容在main.js

但是,<div id="main-content"></div>填充了undefined.

我相信我错过了一些关键的步骤:preload.jsrenderer.js

有人看到事件链丢失的地方了吗?

(我非常愿意接受任何对我的流程的改进)

在下面的代码中插入console.log()'s表示handle内容在openFile之前执行一个返回结果的机会。

main.js(主进程)

function openFile() {
fs.readFile("logs.txt", "utf-8", (err, data) => {
if (err) {
console.error(err);
return "Error Loading Log File";
}
console.log('openFile: ' + data); // Testing
return data;
});
}
ipcMain.handle('channel-load-file', () => {
let result = openFile();
console.log('handle: ' + result); // Testing
return result;
})

console.log()的结果是…

handle: undefined
openFile: File content...

为了解决这个问题,让我们将fs.readFile从回调更改为承诺,因此我们可以在handle中为其await

由于handle处理的是一个promise,让我们使用语法糖asyncawait来更容易实现。

main.js(主进程)

function openFile() {
return new Promise((resolve, reject) => {
fs.readFile("logs.txt", "utf-8", (error, data) => {
if (error) {
console.log('reject: ' + error); // Testing
reject(error);
} else {
console.log('resolve: ' + data); // Testing
resolve(data)
}
});
});
}
ipcMain.handle('channel-load-file', async (event, message) => {
return await openFile()
.then((data) => {
console.log('handle: ' + data); // Testing
return data;
})
.catch((error) => {
console.log('handle error: ' + error); // Testing
return 'Error Loading Log File';
})
});

最后,让我们修改在index.html文件中检索data的方式。

PS:让我们也将.toString()添加到返回的data(只是为了确保)。

index.html(渲染过程)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
</head>
<body>
<div id="main-content"></div>
<input type="button" id="button" value="Load File">
</body>
<script>
document.getElementById('button').addEventListener('click', () => {
window.electronAPI.loadFile()
.then((data) => {
console.log(data); // Testing
document.getElementById("main-content").innerText = data.toString();
});
})
</script>
</html>

最新更新