You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node EventEmitter单次emit后event.on触发两次问题排查(VSCode扩展场景)

问题诊断与修复:SessionManager重复触发事件导致的错误

核心问题

你的代码错误根源在于使用了EventEmitter.on()添加永久事件监听器,而非单次监听器。

错误流程拆解

  1. 第二个、第三个请求进入等待时,都通过event.on()绑定了available事件的监听器,这些监听器不会自动移除
  2. 首个请求调用freeSession触发available事件时,两个监听器会同时被触发:
    • 第二个请求的resolve执行,找到可用会话并标记为inUse,流程正常
    • 第三个请求的resolve也随即执行,但此时会话已被第二个请求占用,findIndex返回-1,后续访问sessionArray[index]直接抛出错误

修复代码

将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 23:56:12