Node EventEmitter单次emit后event.on触发两次问题排查(VSCode扩展场景)
问题诊断与修复:SessionManager重复触发事件导致的错误
核心问题
你的代码错误根源在于使用了EventEmitter.on()添加永久事件监听器,而非单次监听器。
错误流程拆解
- 第二个、第三个请求进入等待时,都通过
event.on()绑定了available事件的监听器,这些监听器不会自动移除 - 首个请求调用
freeSession触发available事件时,两个监听器会同时被触发:- 第二个请求的resolve执行,找到可用会话并标记为
inUse,流程正常 - 第三个请求的resolve也随即执行,但此时会话已被第二个请求占用,
findIndex返回-1,后续访问sessionArray[index]直接抛出错误
- 第二个请求的resolve执行,找到可用会话并标记为
修复代码
将event.on()替换为event.once()(单次触发后自动解绑监听器),同时添加防御性判断避免极端异常:
private event = new EventEmitter(); private sessionArray = []; public async getSession(sessionName: string) { let index: number; index = this.sessionArray.findIndex((a) => a.sessionName === sessionName && a.inUse === false); if (index === -1) { // 改用once,触发一次后自动移除监听器,避免重复响应 await new Promise((resolve) => this.event.once("available", resolve)); index = this.sessionArray.findIndex((a) => a.sessionName === sessionName && a.inUse === false); // 防御性判断:处理会话被意外移除的极端情况 if (index === -1) { throw new Error(`No available session found for ${sessionName} after waiting`); } } this.sessionArray[index].inUse = true; return { session: this.sessionArray[index], id: index }; } /** * set the session status back to available and emit the event */ public async freeSession(id: number) { this.sessionArray[id].inUse = false; this.event.emit("available"); return; }
修复逻辑说明
EventEmitter.once()会在事件触发一次后自动解绑对应的监听器,每个等待的请求只会响应一次available事件- 新增的防御判断可以避免会话被意外从数组中移除时,依然出现
index === -1的崩溃情况
内容的提问来源于stack exchange,提问作者djacks
相关产品推荐
相关产品推荐

