我正在尝试使用网络工作人员将文件导入到我的电子应用程序中,以免阻止我的主进程。我已经完成了他们在 electro-vite 文档中写的所有内容(剧透警报不多),但在调用工作人员时应用程序冻结了。 https://electron-vite.org/guide/dev#worker-threads
当我尝试导入文件时,整个应用程序都冻结了,但只是在视觉上。复制本身可以工作,但是完成后有时应用程序会在一段时间后解冻,有时我需要重新启动它。 我还尝试使用文档中列出的第二种方法在 electro-vite 应用程序中使用工作人员,但它根本没有开始对我大喊大叫 importWorker 没有默认导出,与我在尝试为此实现子进程时遇到的错误相同。这是分支下应用程序的完整代码
workers
https://github.com/UnderMan4/abManager/tree/workers。
这就是我的代码现在的样子:
// main/index.ts
import { importFiles } from "./import";
// Other imports
function createWindow(): void {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1400,
height: 900,
minHeight: 600,
minWidth: 1100,
show: false,
autoHideMenuBar: false,
...(process.platform === "linux" ? { icon } : {}),
webPreferences: {
preload: path.join(__dirname, "../preload/index.js"),
sandbox: false,
nodeIntegrationInWorker: true,
},
});
[...]
apiHandling();
[...]
});
[...]
const apiHandling = () => {
// more communication handling
ipcMain.on("import-files", (_, data) => {
importFiles(data);
});
};
[...]
// main/import.ts
import { ipcMain } from "electron";
import { Worker } from "worker_threads";
import importWorker from "./workers/importWorker?nodeWorker";
const runningImports = new Map<string, { data: ImportData; worker: Worker }>();
// This method will allow my to start importing (copying into library folder). By design every call should create new worker, do all copying in background and send progress to renderer using ipcMain.emit()
export const importFiles = (data: ImportData) => {
if (runningImports.has(data.id)) return;
const worker = importWorker({
workerData: data,
});
runningImports.set(data.id, { data, worker });
worker.on("message", (message: ImportWorkerMessage) => {
const { type, ...data } = message;
ipcMain.emit("import-message", type, data);
if (type === "done") {
worker.terminate();
}
});
worker.on("error", (err) => {
console.error(err);
});
worker.on("exit", (code) => {
runningImports.delete(data.id);
});
};
// main/workers/importWorker.ts
// The worker itself
import fs from "fs";
import p from "path";
import { parentPort, workerData } from "worker_threads";
if (!parentPort) {
throw new Error("No parentPort found");
}
const { paths, options, id } = workerData as ImportData;
const fileQueue = [...paths];
const processFiles = () => {
if (fileQueue.length === 0) {
parentPort!.postMessage({ type: "done", id });
return;
}
//Here I'm copying every file in paths array to desktop (for now)
const path = fileQueue.shift()!;
const fileName = p.basename(path);
const readStream = fs.createReadStream(path);
const writeStream = fs.createWriteStream(
p.join("C:\\Users\\filip\\Desktop", fileName)
);
parentPort!.postMessage({
type: "fileStart",
id,
fileName,
});
readStream.on("data", (chunk) => {
parentPort!.postMessage({
type: "progress",
id,
fileName,
chunkLength: chunk.length,
});
});
readStream.on("end", () => {
parentPort!.postMessage({
type: "fileDone",
id,
fileName,
});
processFiles();
});
readStream.pipe(writeStream);
writeStream.on("error", (error) => {
parentPort!.postMessage({
type: "error",
id,
fileName,
error,
});
});
};
processFiles();
// defining communication methods for renderer in preload/index.ts
import: {
importFiles: (path: string[], options: unknown) => {
ipcRenderer.sendSync("import-files", path, options);
},
onMessage: (callback: (event: unknown, data: unknown) => void) => {
ipcRenderer.addListener("import-message", callback);
return () => ipcRenderer.removeListener("import-message", callback);
},
},
我设法让它工作,但有两个错误:
在
main/index.ts
应该是
ipcMain.handle("import-files", (_, data) => {
importFiles(data);
});
而不是
ipcMain.on("import-files", (_, data) => {
importFiles(data);
});
并在
preload/index.ts
ipcRenderer.invoke("import-files", path, options);
而不是
ipcRenderer.sendSync("import-files", path, options);
现在应用程序不再冻结了