使用socket.io-client出现Maximum call stack size exceeded错误求助
从报错栈可以看出,错误源于WebSocket的错误与关闭事件形成循环调用:
RangeError: Maximum call stack size exceeded
at [nodejs.internal.kHybridDispatch] (node:internal/event_target:824:9)
at WebSocket.dispatchEvent (node:internal/event_target:751:26)
at fireEvent (node:internal/deps/undici/undici:10966:14)
at failWebsocketConnection (node:internal/deps/undici/undici:11040:9)
at WebSocket.close (node:internal/deps/undici/undici:11650:11)
at WS.doClose (C:\Users\User\node_modules\socket.io-client\node_modules\engine.io-client\lib\transports\websocket.js:248:13)
at Transport.close (C:\Users\User\node_modules\socket.io-client\node_modules\engine.io-client\lib\transport.js:98:10)
at Socket.onClose (C:\Users\User\node_modules\socket.io-client\node_modules\engine.io-client\lib\socket.js:713:20)
at Socket.onError (C:\Users\User\node_modules\socket.io-client\node_modules\engine.io-client\lib\socket.js:691:8)
at WS. (C:\Users\User\node_modules\socket.io-client\node_modules\engine.io-client\lib\socket.js:281:10)
核心问题分析
你的代码存在致命逻辑错误:在connect事件回调内重复绑定事件监听器。由于开启了reconnect: true,每次socket断开重连成功时,connect事件都会触发,此时你会再次绑定init、new_item、close、error等事件的监听器。随着重连次数增加,同一个事件会堆积大量监听器,一旦错误或关闭事件触发,所有监听器同时执行,进而引发循环调用,最终导致栈溢出。
修复方案
1. 调整事件监听器绑定位置,避免重复绑定
将所有socket.on()的监听逻辑移到connect事件回调之外,确保每个事件只绑定一次监听器。修改后的代码如下:
async function initSocket() { console.log("Connecting to websocket..."); try { const userData = (await axios.get(`https://${domain}/api/v2/metadata/socket`)).data; const socket = io( socketEndpoint, { transports: ["websocket"], secure: true, rejectUnauthorized: false, reconnect: true, extraHeaders: { 'User-agent': `${userData.user.id} API Bot` } } ); // 事件监听器移至connect回调外,仅绑定一次 socket.on('init', (data) => { if (data && data.authenticated) { console.log(`Successfully authenticated as ${data.name}`); socket.emit('filters', { price_max: 9999999 }); } else { socket.emit('identify', { uid: userData.user.id, model: userData.user, authorizationToken: userData.socket_token, signature: userData.socket_signature }); } }); socket.on('new_item', (data) => { console.log(data) }); socket.on("close", (reason) => console.log(`Socket closed: ${reason}`)); socket.on('error', (data) => console.log(`WS Error: ${data}`)); socket.on('connect_error', (data) => console.log(`Connect Error: ${data}`)); socket.on('connect', () => { console.log(`Connected to websocket`); // 仅保留每次连接成功后需要执行的一次性操作 }); } catch (e) { console.log(`Error while initializing the Socket. Error: ${e}`); } };
2. 降级Node.js版本至v20 LTS
你当前使用的Node.js v22.2.0是较新的版本,其内置WebSocket基于undici库,可能与socket.io-client存在兼容性问题。切换到稳定的v20 LTS版本,可规避这类底层库的兼容性bug。
3. 移除不必要的async标记
connect回调标记为async但未使用await操作,去掉该标记可避免潜在的异步逻辑问题。
内容的提问来源于stack exchange,提问作者Asthma

