如何为遍历WebSocket客户端Set的循环迭代添加间隔延迟?
解决方案
要实现逐个处理空闲客户端、分散服务器负载的需求,你可以用**异步迭代+递归setTimeout**替代原有的setInterval批量处理逻辑,具体改造如下:
核心思路
- 用递归
setTimeout替代setInterval:确保一轮客户端处理全部完成后,再等待下一个检查周期,避免原setInterval可能出现的任务叠加问题。 - 异步遍历客户端集合:每次处理单个客户端后,等待短暂延迟再处理下一个,分散CPU消耗,消除瞬时性能峰值。
改造后的代码
export function terminateIdleConnections() { // 延迟工具函数 const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); // 单个客户端处理后的间隔延迟,可根据服务器性能调整(比如50-200ms) const PER_CLIENT_DELAY = 100; // 异步处理所有客户端的逻辑 async function processIdleConnections() { console.log('开始本轮连接检查', new Date()); // 将Set转为数组,避免遍历过程中客户端断开导致的迭代异常 const clients = Array.from(websocketServer.clients); for (const ws of clients) { try { // @ts-ignore if (ws.isAlive === false) { console.log('终止空闲连接', new Date()); ws.terminate(); } else { console.log('发送ping检测', new Date()); // @ts-ignore ws.isAlive = false; ws.ping(); } // 处理完当前客户端后,等待指定延迟再处理下一个 await delay(PER_CLIENT_DELAY); } catch (err) { // 捕获单个客户端的处理异常,避免中断整个遍历流程 console.error('处理连接时出错:', err); } } } // 递归触发周期性检查 function startCheckCycle() { // 先完成本轮所有客户端处理,再启动下一个周期 processIdleConnections().then(() => { setTimeout(startCheckCycle, WEBSOCKET_CHECK_IDLE_CONNECTION_FREQUENCY); }); } // 启动初始检查循环 const initialTimeout = setTimeout(startCheckCycle, WEBSOCKET_CHECK_IDLE_CONNECTION_FREQUENCY); // 服务器关闭时清理定时器 websocketServer.on('close', function close() { console.log('终止检查循环', new Date()); clearTimeout(initialTimeout); }); }
关键细节说明
Array.from(websocketServer.clients):将Set转为数组,避免遍历过程中客户端突然断开导致Set结构变化,引发迭代异常。try/catch包裹单个客户端处理逻辑:确保某一个客户端处理出错时,不会中断整个遍历流程。- 递归
setTimeout:只有当本轮所有客户端处理完成(包括所有延迟等待)后,才会启动下一个检查周期,彻底避免原setInterval可能出现的任务叠加问题。 - 可调整的
PER_CLIENT_DELAY:根据服务器实际性能和客户端数量,灵活设置延迟时间,平衡处理效率与负载分散效果。
内容的提问来源于stack exchange,提问作者PirateApp
相关产品推荐
相关产品推荐

