NodeJS 7:EventEmitter + await/async

eqzww0vc  于 2023-08-04  发布在  Node.js
关注(0)|答案(2)|浏览(140)

如何在不提供事件发射器的情况下,通过传递给事件发射器的回调来结束async函数?
此外,不使用 * 外部模块 *,只需简单的NodeJS 7.x/8.x(支持Es6语法和async/await)。
基本上,我们希望将async function ...与事件发射器混合使用,以便在事件发射器发出end信号时解析。
还要记住,在使用await完成其他一些异步函数之前,我们不会从事件发射器开始。
如果我们有一个“新的承诺(......)”,我们就称之为决心(resolve);而且我们不能使用'return',因为我们是在回调中。

/*
 * Example of mixing Events + async/await.
 */

// Supose a random pomise'd function like:
function canIHazACheezBurger () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Math.random() > 0.5);
    }, 500 + Math.random() * 500)
  });
}

/**
 * Then, we want to mix an event emitter with this logic,
 * what we want is that this function resolves the promise
 * when the event emitter signals 'end' (for example).
 * Also bear in mind that we won't start with the event emitter
 * until done with the above function.
 * If I had a "new Promise(...)" I would call resolve(); and the
 * headache would be over, but in 'async' there's no 'resolve',
 * plus I cannot use 'return' because I'm inside a callback.
 */
async function bakeMeSomeBurgers () {
  let canIHave = await canIHazACheezBurger();
  // Do something with the result, as an example.
  if (canIHave) {
    console.log('Hehe, you can have...');
  } else {
    console.log('NOPE');
  }
  // Here invoke our event emitter:
  let cook = new BurgerCooking('cheez');
  // Assume that is a normal event emitter, like for handling a download.
  cook.on('update', (percent) => {
    console.log(`The burger is ${percent}% done`);
  });
  // Here lies the problem:
  cook.on('end', () => {
    console.log('I\'ve finished the burger!');
    if (canIHave) {
      console.log('Here, take it :)');
    } else {
      console.log('Too bad you can\'t have it >:)');
    }
    // So, now... What?
    // resolve(); ? nope
    // return; ?
  });
}

字符串

免责声明

我想道歉,如果这个问题已经在某处完成。所做的研究显示了与混合异步和同步逻辑相关的问题,但我没有发现任何关于这一点。
标题中的一个类似问题是this 'write async function with EventEmitter',但它与此问题无关。“

t5zmwmid

t5zmwmid1#

我们可以从传递给事件发射器的回调函数中结束一个异步函数而不承诺事件发射器吗?

. async/await语法只是then调用的糖,依赖于promise。

async function bakeMeSomeBurgers () {
  let canIHave = await canIHazACheezBurger();
  if (canIHave)
    console.log('Hehe, you can have...');
  else
    console.log('NOPE');

  // Here we create and await our promise:
  await new Promise((resolve, reject) => {
    // Here invoke our event emitter:
    let cook = new BurgerCooking('cheez');
    // a normal event callback:
    cook.on('update', percent => {
      console.log(`The burger is ${percent}% done`);
    });
    cook.on('end', resolve); // call resolve when its done
    cook.on('error', reject); // don't forget this
  });

  console.log('I\'ve finished the burger!');
  if (canIHave)
    console.log('Here, take it :)');
  else
    console.log('Too bad, you can\'t have it >:)');
}

字符串

2uluyalo

2uluyalo2#

下面是一个类,它扩展了Node.js EventEmitter以支持异步事件侦听器,并提供了一个函数来等待事件完全处理,然后再继续执行代码的其余部分:

import EventEmitter from 'events';

export const EventResolverSymbol = Symbol.for('EventResolver');

export class AsyncEventEmitter extends EventEmitter {
  private listenerMap = new WeakMap<
    (...args: any[]) => void,
    (...args: any[]) => void
  >();

  emitAsync(eventName: string | symbol, ...args: any[]): Promise<void> {
    return new Promise(async resolve => {
      resolve.prototype.key = EventResolverSymbol;
      super.emit(eventName, ...args, resolve);
    });
  }

  on(eventName: string | symbol, listener: (...args: any[]) => void): this {
    const wrappedListener = async (...args: any[]) => {
      // check if event called from `awaitForEventDone` function
      if (args?.length) {
        const resolver = args[args.length - 1];
        if (
          typeof resolver === 'function' &&
          resolver.prototype.key === EventResolverSymbol
        ) {
          try {
            await listener(...args);
          } catch (e) {}
          return await resolver();
        }
      }
      return await listener(...args);
    };
    this.listenerMap.set(listener, wrappedListener);
    return super.on(eventName, wrappedListener);
  }

  once(eventName: string | symbol, listener: (...args: any[]) => void): this {
    const wrappedListener = async (...args: any[]) => {
      if (args?.length) {
        const resolver = args[args.length - 1];
        if (
          typeof resolver === 'function' &&
          resolver.prototype.key === EventResolverSymbol
        ) {
          try {
            await listener(...args);
          } catch (e) {}
          // remove listeners after the event is done
          this.removeListener(eventName, listener);
          this.removeListener(eventName, wrappedListener);
          return await resolver();
        }
      }
      // remove listeners after the event is done
      this.removeListener(eventName, listener);
      this.removeListener(eventName, wrappedListener);
      return await listener(...args);
    };
    this.listenerMap.set(listener, wrappedListener);
    return super.once(eventName, wrappedListener);
  }

  removeListener(
    eventName: string | symbol,
    listener: (...args: any[]) => void,
  ): this {
    const wrappedListener = this.listenerMap.get(listener);
    if (wrappedListener) {
      this.listenerMap.delete(listener);
      return super.removeListener(eventName, wrappedListener);
    }

    return this;
  }

  off = this.removeListener;
}

字符串

示例

// Create a new async event emitter
 const emitter = new AsyncEventEmitter();
 
 // Define an async event listener
 const listener = async (message: string) => {
   console.log('event start with param: ', message);
   await sleep(5000);
 };
 
 // Listen for 'greet' event
 emitter.on('TestEvent', listener);
 
 // Emit the 'greet' event and wait for it to be done
 emitter.emitAsync('TestEvent', 'Hello World!');
    // will be call after 5000ms delay
   .then(() => console.log('event done'));

相关问题