You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Node线程工作器导致Electron Vite应用冻结?

Electron Vite中Web Worker文件导入导致主进程阻塞问题

我正在Electron Vite应用中尝试用Web Worker实现文件导入,目的是避免阻塞主进程。按官方文档操作后,出现以下问题:

  • 调用Worker时应用出现视觉冻结,文件复制能正常完成,但有时结束后需要等待一段时间才能恢复,甚至要重启应用
  • 尝试文档中第二种Worker使用方式时,应用无法启动,报错提示importWorker无默认导出,和使用子进程时的错误一致

相关代码位于仓库的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 }>();

// 该方法用于启动导入(复制到库文件夹),设计上每次调用都会创建新Worker,在后台完成复制并通过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);
   });
};

Worker文件 main/workers/importWorker.ts

// Worker逻辑

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;
   }

   // 目前将paths数组中的每个文件复制到桌面

   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();

Preload文件 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);
   },
},

内容的提问来源于stack exchange,提问作者UnderMan4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 15:42:27