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

Node.js嵌套使用WebSocket出现EventEmitter内存泄漏问题排查

问题原因

你的泄漏问题完全是编码逻辑不规范导致的,和WebSocket堆叠使用没有关系,问题集中在wsServer的connection回调内的冗余注册逻辑:

  • 你将全局单例的Twitch聊天客户端client的PRIVMSG事件监听放在了连接回调里,每有一个新客户端连接你的本地WebSocket服务,就会给client新增一个独立的PRIVMSG监听器,Node.js的EventEmitter默认监听器数量阈值是10,当连接数超过10就会触发泄漏警告。
  • 你还在连接回调里重复注册了process.uncaughtException全局异常监听器、重复执行client.connect()和client.join("channel")逻辑,这部分属于完全冗余的错误操作。
  • 更严重的是这些绑定的监听器不会随着本地WebSocket连接断开而自动销毁,还会持有已经失效的socket对象引用,不仅会触发警告,还会造成真实的内存泄漏,甚至在给已断开连接的socket发消息时抛出异常。
修复方案
  1. 将Twitch客户端的事件监听、连接、加频道逻辑全部移到全局作用域,仅执行一次
  2. 维护一个存活的本地WebSocket连接池,收到Twitch消息时遍历连接池转发消息
  3. 本地WebSocket连接断开时,及时从连接池移除对应的实例,避免残留引用

修复后代码如下:

const { paintballShot } = require('./JavaScript/paintballGunFire');
const { readPin } = require('./JavaScript/readPin');
const ws = require('ws');
const express = require('express');

const app = express();
// 维护存活的本地WebSocket连接池
const connectedSockets = new Set();

//CONNECT TO TWITCH
let client = new ChatClient({
  connection: {
    type: "websocket",
    secure: true,
  }
});

// Twitch事件监听全部移到全局,只注册一次
client.on("ready", () => console.log("Successfully connected to chat"));
client.on("close", (error) => {
  if (error != null) {
    console.error("Client closed due to error", error);
  }
});
// PRIVMSG监听全局只注册一次
client.on("PRIVMSG", (msg, error) => {
  const sendContent = JSON.stringify(`${msg.displayName}: ${msg.messageText}`);
  // 遍历所有存活的连接转发消息
  for (const socket of connectedSockets) {
    if (socket.readyState === ws.OPEN) {
      if (["right", "left", "fire"].includes(msg.messageText)) {
        socket.send(sendContent);
      }
    }
  }

  if (msg.messageText === "fire") {
    paintballShot();
  }
  if (msg.messageText === "pin") {
    readPin();
  }
});
// Twitch连接、加频道逻辑全局只执行一次
client.connect();
client.join("channel");

//create headless websocket
const wsServer = new ws.Server({ noServer: true });
wsServer.on('connection', function connection(socket) {
  // 新连接加入连接池
  connectedSockets.add(socket);
  
  socket.on('message', message => console.log(message));
  // 连接断开时从池子里移除
  socket.on('close', () => {
    connectedSockets.delete(socket);
  });
});

// `server` is a vanilla Node.js HTTP server
const server = app.listen(3000);
server.on('upgrade', (request, socket, head) => {
  wsServer.handleUpgrade(request, socket, head, socket => {
    wsServer.emit('connection', socket, request);
  });
});

process.on('uncaughtException', function (err) {
  console.log(err);
});

内容的提问来源于stack exchange,提问作者J. Doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 12:45:04