事件触发时解决Promise而不重复事件侦听器

时间:2018-03-30 22:58:41

标签: javascript node.js typescript promise eventemitter

我试图在触发EventEmitter事件时解决一个承诺。

contains函数接受一个参数并将其添加到堆栈中。然后将项目从堆栈中取出以进行任意处理,并触发successerror事件。

public async processData(payload: Payload) {
  // Push data onto a stack
  this._myStack.push(payload);

  return new Promise((resolve, reject) => {
    myEventEmitter.on('processSuccess', data => {
      resolve(data);
    });

    myEventEmitter.on('processError', error => {
      reject(error);
    });
  });
}

问题是每次将项添加到堆栈时都会添加一个新的侦听器。这意味着当发出processSuccessprocessError事件时,将为堆栈中的每个项目返回承诺。

示例:如果堆叠中有11个项目并且发出processSuccess,则data将返回11次。

当发布其中一个事件而没有为堆栈中的每个项目返回时,是否有办法解决一个承诺?也就是说,如何在不为每个事件创建一堆事件侦听器的情况下实现此目的?

3 个答案:

答案 0 :(得分:0)

使用事件命名空间。参考https://css-tricks.com/namespaced-events-jquery/

为事件创建某种动态命名空间,并对该命名空间运行检查以匹配公共事件侦听器。在任何命名空间匹配时解析promise。

答案 1 :(得分:0)

所以基本上为了得到一个好的答案,我需要更多的信息,但总的来说,你可以做到以下几点:

  • Payload应具有唯一ID
  • 数据响应应包含相同的ID
  • 错误响应应包含相同的ID

因此,基于您的有效负载对象应该是这样的:

{"id": ..., ....}

响应数据对象

class MyClass {
    private _myStack: Array<Payload>;
    private _promisesFunctions: Array<any>;

    constructor() {
        myEventEmitter.on('processSuccess', data => {
            this._promisesFunctions[data.id].resolve(data);
        });

        myEventEmitter.on('processError', error => {
            this._promisesFunctions[error.id].reject(error);
        });
    }

    public async processData(payload: Payload) {
        // Push data onto a stack
        this._myStack.push(payload);

        return await new Promise(async (resolve, reject) => {
            this._promisesFunctions[payload.id] = { resolve, reject };
        });
    }
 }

错误数据对象

{{1}}

您可以轻松地执行以下操作:

&#13;
&#13;
{{1}}
&#13;
&#13;
&#13;

如果您没有这种可能性,或者您无法控制这3个对象,请提供所有这3个对象的示例或至少有关此问题的更多信息,我会更新我的回复

答案 2 :(得分:0)

假设您可以使用随事件发送的data本身的有效负载标识信息(成功和错误),那么您可以这样做:

public processData(payload: Payload) {
    // Push data onto a stack
    this._myStack.push(payload);

    return new Promise((resolve, reject) => {

      function resolver(data) {
        // if this event belongs to this payload
        if (data.payload === payload) {
          resolve(data);
          clearHandlers();
        }
      }

      function rejecter(error) {
        // if this event belongs to this payload
        if (error.payload === payload) {
          reject(error);
          clearHandlers();
        }
      }

      // clear event handlers
      function clearHandlers() {
        myEventEmitter.removeListener('processSuccess', resolver);
        myEventEmitter.removeListener('processError', rejecter);
      }

      myEventEmitter.on('processSuccess', resolver);  
      myEventEmitter.on('processError', rejecter);
    });
}

如果您无法确定哪个有效负载与哪个事件相对应,那么使用此常规结构的唯一方法是永远不要将相同的myEventEmitter用于多个processData()操作时间。这是因为您需要确保在processSuccessprocessError事件发生时,您确切知道它属于哪个有效负载。您必须知道,以避免同时在飞行中的单独异步操作之间的交叉耦合。这可以通过四种方式实现:

  1. 有效负载是每个事件的一部分,因此您可以进行比较以查看它是否是正确的有效负载(就像在我的第一个代码示例中一样)。
  2. 永远不会在同时飞行的操作之间共享myEventEmitter对象。
  3. 没有两个使用共享myEventEmitter的异步操作同时在飞行中。
  4. 你以某种方式召唤出独特的消息名称来监听和触发正在运行的每个单独的有效负载。这也需要与事件触发方面的合作。
  5. 对于上面的选项#2或#3,您可以使用以下代码:

    public processData(payload: Payload) {
        // Push data onto a stack
        this._myStack.push(payload);
    
        return new Promise((resolve, reject) => {
          function resolver(data) {
            resolve(data);
            clearHandlers();
          }
          function rejecter(err) {
            reject(error);
            clearHandlers();
          }
          // clear event handlers
          function clearHandlers() {
            myEventEmitter.removeListener('processSuccess', resolver);
            myEventEmitter.removeListener('processError', rejecter);
          }
    
          myEventEmitter.on('processSuccess', resolver);  
          myEventEmitter.on('processError', rejecter);
        });
    }