如何在医生响应时终止Socket事件执行并获取响应用户ID
解决医生呼叫系统的接受响应终止循环问题
你的核心问题在于用了同步的sleep阻塞事件循环,这不仅会让服务器无法处理其他请求,还没法实时响应医生的接受操作。要实现“医生接受后终止流程”,得用异步非阻塞的方式处理,结合Promise.race来同时等待超时和医生的接受事件。
具体实现步骤:
- 替换同步sleep为异步的超时Promise,避免阻塞Node.js事件循环。
- 为每个医生的呼叫,监听一次
emergencyCallAccepted事件(用socket.once自动移除监听器,防止内存泄漏)。 - 用
Promise.race同时等待“5秒超时”和“医生接受”两个结果,哪个先触发就执行对应逻辑。 - 一旦有医生接受,立即终止循环,不再呼叫下一位医生。
修改后的代码:
socket.on("CallingForEmergencyDoctor", async (user) => { let acceptedDoctorId = null; // 遍历在线医生,逐个发起呼叫 for (const doctor of activeEmergencyDoctors) { if (acceptedDoctorId) break; // 已有医生接受,终止循环 console.log(`Request sent to user | userId: ${doctor.userId}`); // 向当前医生发起呼叫 socket.to(doctor.socketId).emit("emergencyDoctorCall"); // 创建两个Promise:一个等待医生接受,一个等待5秒超时 const acceptPromise = new Promise((resolve) => { // 监听医生的接受事件,只监听一次 socket.once("emergencyCallAccepted", (receivedUserId) => { if (receivedUserId === doctor.userId) { resolve(receivedUserId); } }); }); const timeoutPromise = new Promise((resolve) => { setTimeout(() => resolve(null), 5000); }); // 等待先发生的事件:接受或超时 acceptedDoctorId = await Promise.race([acceptPromise, timeoutPromise]); // 无论是否接受,都断开当前医生的呼叫通知 socket.to(doctor.socketId).emit("emergencyCallDisconnect"); // 如果有医生接受,跳出循环 if (acceptedDoctorId) { console.log(`Doctor ${acceptedDoctorId} accepted the emergency call`); break; } } if (!acceptedDoctorId) { console.log("No doctor available"); } });
关键细节说明:
- 异步循环:用
async/await配合for...of实现逐个异步处理,不会阻塞服务器。 Promise.race:同时监听医生接受和超时事件,确保能实时响应医生的操作,而不是硬等5秒。socket.once:只监听一次接受事件,避免同一个患者的呼叫重复触发监听器,防止内存泄漏。- 接受验证:对比收到的
userId和当前呼叫的医生ID,避免其他医生的接受操作干扰当前流程。
医生端需要配合的逻辑:
医生APP在点击接受按钮时,需要向服务器发送emergencyCallAccepted事件,并带上自己的userId:
// 医生端代码示例 socket.emit("emergencyCallAccepted", currentDoctorId);
内容的提问来源于stack exchange,提问作者Munna Khandakar
相关产品推荐
相关产品推荐

