Express+Socket.IO下如何无延迟处理并发请求?
问题本质
Node.js 基于单线程事件循环模型运行,Socket.IO的事件处理默认在主线程执行。如果某个事件处理(比如遍历大量记录并持续调用socket.emit)占用主线程时间过长,会直接阻塞事件循环——后续的请求或事件只能等当前耗时任务完成后才能被处理,这就是你遇到的延迟问题。
解决办法
1. 拆分大响应为分批发送
别一次性把所有记录砸给客户端,拆成多个小批次发送,每发完一批就用setImmediate让出事件循环,给其他请求腾位置。
服务器端示例:
socket.on('get-large-data', async () => { // 假设这是获取海量数据的异步方法 const allRecords = await fetchAllLargeRecords(); const batchSize = 100; // 每批发100条 let current = 0; function sendNextBatch() { if (current >= allRecords.length) { socket.emit('large-data-done'); // 告诉客户端全部发完了 return; } const batch = allRecords.slice(current, current + batchSize); socket.emit('large-data-batch', batch); current += batchSize; setImmediate(sendNextBatch); // 让出主线程,处理其他请求 } sendNextBatch(); });
客户端只需要监听large-data-batch接收分批数据,最后监听large-data-done确认完成即可。
2. 用Worker Threads隔离耗时任务
把数据查询、格式化这类耗时操作丢到Node.js的Worker Threads(子线程)里执行,主线程只负责Socket.IO的消息收发,完全不被阻塞。
先写一个子线程文件data-worker.js:
const { parentPort } = require('worker_threads'); parentPort.on('message', async (task) => { if (task.type === 'fetch-big-data') { // 这里做耗时的数据处理 const processedData = await heavyDataProcessing(); parentPort.postMessage({ type: 'result', data: processedData }); } });
主线程里调用:
const { Worker } = require('worker_threads'); socket.on('get-large-data', () => { const worker = new Worker('./data-worker.js'); worker.postMessage({ type: 'fetch-big-data' }); worker.on('message', (res) => { // 拿到子线程处理好的数据后,再发给客户端(也可以继续分批发) socket.emit('large-data', res.data); worker.terminate(); }); worker.on('error', (err) => { socket.emit('data-error', err.message); worker.terminate(); }); });
3. 优化数据传输格式
如果传输的是结构化数据,用二进制序列化格式(比如MessagePack、Protocol Buffers)替代JSON,能大幅减少数据体积和序列化/反序列化的耗时,间接降低主线程的负载。
示例:用socket.io-msgpack-parser替换默认的JSON解析器
// 服务器端 const { Server } = require('socket.io'); const msgpackParser = require('socket.io-msgpack-parser'); const io = new Server(httpServer, { parser: msgpackParser }); // 客户端也要对应引入并使用该解析器
4. 绝对避免同步耗时操作
所有涉及IO的操作(数据库查询、文件读写)必须用异步API,绝对不能用同步版本(比如fs.readFileSync、db.querySync)——同步操作会直接卡死事件循环,所有请求都会被堵死。
内容的提问来源于stack exchange,提问作者Parisa Seif
相关产品推荐
相关产品推荐

