EventEmitter中发生意外的异步行为

时间:2019-06-25 13:15:36

标签: node.js

我使用EventEmitter如下:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

function c2(num) {
  return new Promise((resolve) => {
    resolve(`c2: ${num}`);
  });
}

// eslint-disable-next-line no-underscore-dangle
// eslint-disable-next-line no-console
const doSomeStuff = async (number) => {
  try {
    console.log(`doSomeStuff: ${number}`);
    const r2 = await c2(number);
    console.log(r2);
  } catch (err) {
    throw err;
  }
};

myEmitter.on('eventOne', async (n) => {
  await doSomeStuff(n);
});

myEmitter.emit('eventOne', 1);
myEmitter.emit('eventOne', 2);
myEmitter.emit('eventOne', 3);
myEmitter.emit('eventOne', 4);

我希望得到一个结果

doSomeStuff: 1
c2: 1
doSomeStuff: 2
c2: 2
doSomeStuff: 3
c2: 3
doSomeStuff: 4
c2: 4

但是输出显示了我

doSomeStuff: 1
doSomeStuff: 2
doSomeStuff: 3
doSomeStuff: 4
c2: 1
c2: 2
c2: 3
c2: 4

据我了解,EventEmitter同步调用事件回调函数,但是由于某种原因,在调用下一个回调函数之前,该回调函数尚未完成执行。我想我这里缺少一些非常基本的东西。

2 个答案:

答案 0 :(得分:2)

事件处理程序不关心函数的async性质。实际上,它根本不关心返回值。只要听到事件,它就会尽快调用它,并且每次听到事件时,它将继续触发。不管它是否已经在运行一个函数。

myEmitter.on('eventOne', async (n) => {
  await doSomeStuff(n);
});

实际上与没有异步/等待的情况完全相同:

myEmitter.on('eventOne', (n) => {
  doSomeStuff(n);
});

假设,您可以稍微调整代码,以便您执行以获取期望的输出。但是,您需要引入单数路径上下文,以使每个发射器都影响一件事情,而不是每个事件都触发其自己的doSomeStuff实例。这是使用生成器函数的示例:

// EventEmitter Polyfill
class EventEmitter {
  constructor() {this._listeners = new Map();}
  on(e, cb) {this._listeners.set(e, [...(this._listeners.get(e) || []), cb]);}
  emit(e, payload) {for (const listener of (this._listeners.get(e) || [])) listener(payload);}
}

const myEmitter = new EventEmitter();

function c2(num) {
  return new Promise(resolve => {
    resolve(`c2: ${num}`);
  });
}

async function* doSomeStuff() {
  while (true) {
    try {
      const number = yield;
      console.log(`doSomeStuff: ${number}`);
      const r2 = await c2(number);
      console.log(r2);
    } catch (err) {
      throw err;
    }
  }
}

const someStuff = doSomeStuff();
someStuff.next(); // Start it

myEmitter.on("eventOne", n => {
  someStuff.next(n);
});

myEmitter.emit("eventOne", 1);
myEmitter.emit("eventOne", 2);
myEmitter.emit("eventOne", 3);
myEmitter.emit("eventOne", 4);

答案 1 :(得分:1)

按照上述逻辑,这是我的意见:

//You emitted event asynchronous, so the listeners will be called asynchronous in [A] scope
myEmitter.emit('eventOne', 1); // all 
myEmitter.emit('eventOne', 2); // of
myEmitter.emit('eventOne', 3); // us
myEmitter.emit('eventOne', 4); // start at almost the same time.

// In listener:
await doSomeStuff(n); // I run synchronously inside [event 1] scope, not [A] scope
await doSomeStuff(n); // I run synchronously inside [event 2] scope, not [A] scope
await doSomeStuff(n); // I run synchronously inside [event 3] scope, not [A] scope
await doSomeStuff(n); // I run synchronously inside [event 4] scope, not [A] scope

,其余的将异步解决。

简述:事件会异步发出,因此监听器没有理由 SYNC 连续发