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

Electron使用win.webContents.send报错Object has been destroyed的解决方法

Electron终端开发:解决「Object has been destroyed」错误

我在Electron应用中开发类似VSCode的终端功能,使用node-pty创建终端后,尝试通过win.webContents.send向渲染进程发送终端数据时,出现「Object has been destroyed」错误。需要解决该问题,实现无错误地向渲染进程回传数据。

错误截图

错误提示

现有代码

主进程代码

const { app, BrowserWindow, ipcMain } = require('electron')
const path = require("path")
require('@electron/remote/main').initialize()


const createMainWindow = () => {
    const win = new BrowserWindow({
        width: 1920,
        height: 1080,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
            enableRemoteModule: true,
            devTools: true
        },
        resizable: true,
        frame: false,
        devTools: true,
        contextIsolation: false,
        enableRemoteModule: true,
        //icon: path.join(__dirname + '/relico.ico'),
    })

    win.loadFile('./page-app/index.html')
    require('@electron/remote/main').enable(win.webContents)
}

const createLoaderWindow = () => {
    const win = new BrowserWindow({
        width: 300,
        height: 400,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
            enableRemoteModule: true,
            devTools: true
        },
        resizable: false,
        frame: false,
        devTools: true,
        contextIsolation: false,
        enableRemoteModule: true,
        //icon: path.join(__dirname + '/relico.ico'),
    })

    win.loadFile('./page-app/loader.html')

    const pty = require("node-pty");
    const os = require("os");
    var shell = os.platform() === "win32" ? "powershell.exe" : "bash";

    var ptyProcess = pty.spawn(shell, [], {
        name: "xterm-color",
        cols: 80,
        rows: 30,
        cwd: process.env.HOME,
        env: process.env
    });

    ptyProcess.onData((data) => {
        process.stdout.write(data);
        win.webContents.send('terminal.incomingData', data);
    });


    ipcMain.on("terminal.keystroke", (event, key) => {
        console.log("KEY:", key)
        ptyProcess.write(key);
    });

    require('@electron/remote/main').enable(win.webContents)

}



app.whenReady().then(createLoaderWindow)

ipcMain.handle('openMain', async () => {
    createMainWindow();
    return true;
})

渲染进程代码

const { Terminal } = require('xterm');
const { FitAddon } = require('xterm-addon-fit');
const { WebLinksAddon } = require('xterm-addon-web-links');
const os = require('os');

var term = new Terminal({
    cursorBlink: true,
    fontFamily: 'monospace',
    fontSize: 14,
    lineHeight: 1.4,
    scrollback: 1000,
});
term.open(document.getElementById('terminal'));

ipcRenderer.on("terminal.incomingData", (event, data) => {
    console.log("INCOMING:")
    console.dir(data);
    term.write(data);
});

term.onData(e => {
    console.dir(e)
    ipcRenderer.send("terminal.keystroke", e);
});

问题原因

错误核心是:当loaderWindow被销毁(比如关闭窗口或切换到主窗口后),node-pty创建的ptyProcess仍在运行,其onData回调会尝试访问已销毁的win对象,触发「Object has been destroyed」错误。此外,IPC事件terminal.keystroke在createLoaderWindow内重复绑定,也可能引发后续问题。

解决方案

1. 窗口关闭时销毁pty进程并移除IPC监听

在createLoaderWindow中添加窗口关闭事件监听,确保窗口销毁时终止pty进程,同时移除对应的IPC事件监听:

win.on('close', () => {
  // 终止pty进程
  if (ptyProcess) {
    ptyProcess.kill();
    ptyProcess = null;
  }
  // 移除IPC事件监听
  ipcMain.removeListener("terminal.keystroke", handleTerminalKeystroke);
});

2. 发送IPC前检查窗口状态

在ptyProcess.onData回调中,先判断窗口是否存活,再发送数据:

ptyProcess.onData((data) => {
  process.stdout.write(data);
  // 确认窗口未被销毁后再发送数据
  if (win && !win.isDestroyed()) {
    win.webContents.send('terminal.incomingData', data);
  }
});

3. 避免IPC事件重复绑定

将terminal.keystroke的处理函数抽离,防止多次调用createLoaderWindow时重复绑定:

// 单独定义处理函数
const handleTerminalKeystroke = (event, key) => {
  console.log("KEY:", key);
  if (ptyProcess) {
    ptyProcess.write(key);
  }
};

// 绑定IPC事件
ipcMain.on("terminal.keystroke", handleTerminalKeystroke);

4. 窗口加载完成后初始化pty(可选)

等待窗口页面加载完成后再创建pty进程,避免窗口未就绪时发送IPC:

win.webContents.on('did-finish-load', () => {
  const pty = require("node-pty");
  const os = require("os");
  var shell = os.platform() === "win32" ? "powershell.exe" : "bash";

  var ptyProcess = pty.spawn(shell, [], {
    name: "xterm-color",
    cols: 80,
    rows: 30,
    cwd: process.env.HOME,
    env: process.env
  });

  // 后续的onData和IPC绑定逻辑放在这里
});

修改后的主进程代码示例

const { app, BrowserWindow, ipcMain } = require('electron')
const path = require("path")
require('@electron/remote/main').initialize()


const createMainWindow = () => {
    const win = new BrowserWindow({
        width: 1920,
        height: 1080,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
            enableRemoteModule: true,
            devTools: true
        },
        resizable: true,
        frame: false,
        devTools: true,
        contextIsolation: false,
        enableRemoteModule: true,
        //icon: path.join(__dirname + '/relico.ico'),
    })

    win.loadFile('./page-app/index.html')
    require('@electron/remote/main').enable(win.webContents)
}

const createLoaderWindow = () => {
    const win = new BrowserWindow({
        width: 300,
        height: 400,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
            enableRemoteModule: true,
            devTools: true
        },
        resizable: false,
        frame: false,
        devTools: true,
        contextIsolation: false,
        enableRemoteModule: true,
        //icon: path.join(__dirname + '/relico.ico'),
    })

    win.loadFile('./page-app/loader.html')

    let ptyProcess = null;
    const handleTerminalKeystroke = (event, key) => {
        console.log("KEY:", key)
        if (ptyProcess) {
            ptyProcess.write(key);
        }
    };

    // 窗口加载完成后初始化pty
    win.webContents.on('did-finish-load', () => {
        const pty = require("node-pty");
        const os = require("os");
        var shell = os.platform() === "win32" ? "powershell.exe" : "bash";

        ptyProcess = pty.spawn(shell, [], {
            name: "xterm-color",
            cols: 80,
            rows: 30,
            cwd: process.env.HOME,
            env: process.env
        });

        ptyProcess.onData((data) => {
            process.stdout.write(data);
            // 检查窗口状态后发送数据
            if (win && !win.isDestroyed()) {
                win.webContents.send('terminal.incomingData', data);
            }
        });

        ipcMain.on("terminal.keystroke", handleTerminalKeystroke);
    });

    // 窗口关闭时清理资源
    win.on('close', () => {
        if (ptyProcess) {
            ptyProcess.kill();
            ptyProcess = null;
        }
        ipcMain.removeListener("terminal.keystroke", handleTerminalKeystroke);
    });

    require('@electron/remote/main').enable(win.webContents)
}



app.whenReady().then(createLoaderWindow)

ipcMain.handle('openMain', async () => {
    createMainWindow();
    return true;
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 17:54:59