Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJS 7: EventEmitter + await/async

How we can end an async function from a callback passed to an event emitter without promisifing the event emitter?

Also without using external modules, just plain NodeJS 7.x/8.x (Which supports Es6 syntax and async/await.

We want basically to mix an async function ... with an event emitter, so that it resolves when the event emitter signals end.

Also bear in mind that we won't start with the event emitter until done with some other async functions, using await.

If we had a "new Promise(...)" we would call resolve(); and the headache would be over, but in 'async' there's no 'resolve', plus we cannot use 'return' because we're inside a callback.

/*
 * 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; ?
  });
}

Disclaimer

I want to apologize if this question is already done somewhere. The research done shows questions related to mix async with sync logic, but I've found nothing about this.

A similar question in title is this 'write async function with EventEmitter' but it has nothing to do with this question.

like image 334
SigmaSoldier Avatar asked Aug 30 '17 18:08

SigmaSoldier


1 Answers

Can we end an async function from a callback passed to an event emitter without promisifing the event emitter?

No. async/await syntax is just sugar for then calls and relies on promises.

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 >:)');
}
like image 172
Bergi Avatar answered Sep 19 '22 14:09

Bergi