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

如何实现带once和on方法的Promise?结合EventEmitter方案求教

实现融合Promise与EventEmitter的事务处理对象(参考web3.js风格)

核心思路

要实现像web3.js那样同时支持on/once事件监听和then/catch Promise链式调用的对象,核心是让Promise实例拥有EventEmitter的事件管理能力。具体做法是:

  • 用EventEmitter(或自定义实现)处理事件的订阅与触发
  • 创建Promise管理事务的异步生命周期(完成/失败)
  • 将EventEmitter的on/once/off方法挂载到Promise实例上,实现流畅的链式调用

完整代码实现(Node.js环境)

const { EventEmitter } = require('events');

function createTransaction() {
  // 初始化事件发射器
  const emitter = new EventEmitter();

  // 创建Promise,封装事务逻辑
  const transactionPromise = new Promise((resolve, reject) => {
    console.log('事务启动');

    // 模拟txn_id生成逻辑(1秒后生成)
    setTimeout(() => {
      const txnId = `txn_${Math.random().toString(36).slice(2, 11)}`;
      emitter.emit('idCreated', txnId);
    }, 1000);

    // 模拟剩余时间推送(每秒更新一次)
    let remainingSeconds = 5;
    const timeTimer = setInterval(() => {
      remainingSeconds--;
      emitter.emit('timeLeft', remainingSeconds);

      if (remainingSeconds === 0) {
        clearInterval(timeTimer);
        // 事务完成,返回结果
        resolve({ status: 'completed', txnId: `txn_${Math.random().toString(36).slice(2, 11)}` });
      }
    }, 1000);

    // 可选:模拟事务失败场景
    // setTimeout(() => {
    //   clearInterval(timeTimer);
    //   const error = new Error('事务执行超时');
    //   emitter.emit('error', error);
    //   reject(error);
    // }, 3000);
  });

  // 将EventEmitter的方法绑定到Promise实例,实现链式调用
  transactionPromise.on = emitter.on.bind(emitter);
  transactionPromise.once = emitter.once.bind(emitter);
  transactionPromise.off = emitter.off.bind(emitter);

  return transactionPromise;
}

// 使用示例
createTransaction()
  .once('idCreated', (txnId) => {
    console.log('txn_id已生成:', txnId);
  })
  .on('timeLeft', (seconds) => {
    console.log('剩余预估时间:', `${seconds}秒`);
  })
  .then((result) => {
    console.log('事务执行完成:', result);
  })
  .catch((error) => {
    console.error('事务执行失败:', error);
  });

浏览器环境适配

如果是浏览器环境,没有Node.js的events模块,可以自己实现一个简易版EventEmitter:

class SimpleEventEmitter {
  constructor() {
    this.eventMap = new Map();
  }

  on(eventName, handler) {
    if (!this.eventMap.has(eventName)) {
      this.eventMap.set(eventName, []);
    }
    this.eventMap.get(eventName).push(handler);
    return this;
  }

  once(eventName, handler) {
    const onceHandler = (...args) => {
      handler(...args);
      this.off(eventName, onceHandler);
    };
    this.on(eventName, onceHandler);
    return this;
  }

  off(eventName, handler) {
    if (!this.eventMap.has(eventName)) return;
    const handlers = this.eventMap.get(eventName);
    this.eventMap.set(eventName, handlers.filter(h => h !== handler));
  }

  emit(eventName, ...args) {
    if (!this.eventMap.has(eventName)) return;
    this.eventMap.get(eventName).forEach(handler => handler(...args));
  }
}

// 替换createTransaction里的EventEmitter为SimpleEventEmitter即可

关键细节说明

  • 事件与Promise的联动:事务中的关键节点(如txn_id生成、剩余时间更新)通过emitter.emit触发事件,事务完成/失败通过Promise的resolve/reject处理
  • 链式调用支持:通过将EventEmitter的方法绑定到Promise实例,实现像web3.js那样的on().once().then()链式调用
  • 内存泄漏防范:事务完成或失败时,要及时清除定时器等异步任务,避免内存泄漏
  • 错误处理:可以同时通过on('error')监听错误和catch()捕获错误,提升灵活性

内容的提问来源于stack exchange,提问作者CodingWithRoyal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 01:20:36