-1

I have synchronous work logic, I want to convert it to asynchronous event driven code.

How can I make async foo return the promisified value of the callback ( done() || fail() ) at the end of the event chain?

Like make this oversimplified example works

async function foo(param){
  eventEmitter.emit('first-event', param);
}

eventEmitter.on('first-event', /*Do something*/);
.
.
.
eventEmitter.on('last-event', (payload) => {
  try{
   /*If no error*/
   eventEmitter.emit('done', payload);
  }catch{
   /*If error*/
   eventEmitter.emit('fail', error);
  }
});

function done(payload){
  return ({payload:payload});
}

function fail(error){
  return ({fail:error});
}

eventEmitter.on('done', payload => done(payload) );

eventEmitter.on('error', error => fail(error) );

if anyone has information about it thanks for sharing it and your time, sorry for any mistakes.

LT-Sites
  • 375
  • 5
  • 15
  • 1
    "*I want to convert it to asynchronous event driven code.*" - why? Can you post your working synchronous logic, and tell us how it does not meet your requirements any more? – Bergi Aug 30 '20 at 16:22
  • In general, just [use `return events.once(eventEmitter, 'done');`](https://nodejs.org/api/events.html#events_events_once_emitter_name) (and use `'error'`, not `'fail'`) – Bergi Aug 30 '20 at 16:25
  • Use constructor functions –  Aug 30 '20 at 17:04
  • @Thomas Uh, no? – Bergi Aug 30 '20 at 17:05
  • @Bergi "Can you post your working synchronous logic, and tell us how it does not meet your requirements any more?" is not about requirements is about convert it to events emitted – LT-Sites Aug 30 '20 at 23:48
  • @LT-Sites Then I challenge you by saying that events are the wrong solution and you should not use them. – Bergi Aug 31 '20 at 07:18

2 Answers2

0

If you have to do this, promise constructor will work:

let p = {};
async function foo(param) {
  eventEmitter.emit('first-event', param);
  return await new Promise((res, rej) => (p.res = res) && (p.rej = rej));
}
//...
eventEmitter.on('done', payload => done(payload) && p.res());

eventEmitter.on('error', error => fail(error) && p.rej());

TheMaster
  • 45,448
  • 6
  • 62
  • 85
  • No, don't do that. Instead of exporting the `reject` and `resolve` functions, just move the `on()` calls inside the `new Promise` executor. – Bergi Aug 30 '20 at 17:06
  • @Bergi Any specific reason against the export? If I put it in, it might look like callback hell, if code grows. – TheMaster Aug 30 '20 at 17:07
  • [Using the `Promise` constructor as supposed](https://stackoverflow.com/q/37651780/1048572), not creating [an unnecessary deferred](https://stackoverflow.com/q/32853105/1048572), less fragility because of the mutable `p`, less variables in the global scope, better control over who can resolve the promise (no access to `p`), and in general much simpler code and better error handling. – Bergi Aug 30 '20 at 17:13
  • 1
    In fact I'd even argue that your code is broken since it cannot work if `foo()` is called multiple times, but it probably wouldn't work anyway given the way the `eventEmitter` is set up by the OP. – Bergi Aug 30 '20 at 17:15
  • Also no, we use promises to *avoid* callback hell: if the code grows, it will grow outside of the `new Promise`, after the `await` - that's the whole point of the exercise. – Bergi Aug 30 '20 at 17:18
  • @Bergi Thank you for the explanations and links. I'll read up. – TheMaster Aug 30 '20 at 17:20
-1

After much reading the comments and links of:

@Bergi 
@TheMaster
@Thomas

I think I have found the best solution I hope I am not wrong, if I am, I hope it is not too much to ask that the people who respond, do so with the intention of solving the problem instead of just pointing out an error or that something does not like.

"Please, show me the code! " instead ;)

This is a example of the dumbest way to split a String using eventEmitter, async await and this aproach and Works!

let event = new(require('events').EventEmitter);

async function split(string) {

  let holder = {};
  let promise = async() => {
    return await (holder.payload || holder.error) ? holder : null;
  }

  event.on('done', data => done(data));

  function done(data) {
    try {
      console.log('Done emitted');
      console.log(`Param: ${data}`);
      holder.payload = data;
    } catch(error) {
      console.log(error);
    }
  }

  event.on('error', error => fail(error));

  function fail(error) {
    try {
      console.log('Fail emitted');
      console.log(`Param: ${error}`);
      holder.error = error;
    } catch(error) {
      console.log(error);
    }
  }

  event.on('split', async(string) => {
    try {
      console.log('Split emitted');
      console.log(`Param : ${string}`);
      const data = string.split(' ');
      event.emit('done', data);
    } catch(error) {
      console.log(error);
      event.emit('error', error);
    }
  });

  try {
    event.emit('split', string);
    return({ payload: await promise().then(data => { return data.payload }) });
  } catch(error) {
    console.log(error);
  }

}

console.clear()
console.log(
  split('Hello world').then(data => {
    console.log('Split done!');
    console.log(data);
  })
);

So at this point var 'holder' and function 'promise' are inside the scoop of the function 'split' and all the console outputs are:

Split emitted
Param : Hello world
Done emitted
Param: Hello,world
Promise { <pending> }
Split done!
{ payload: [ 'Hello', 'world' ] }

The whole point is to ilustrate that it is possible to have n asynchronous events, callbacks and promises and be able to return a value, after a process of n stages or events

thanks for your time guys, and any other comments, sorry for any mistakes.

LT-Sites
  • 375
  • 5
  • 15
  • "*I think I have found the best solution*" - no, you haven't. There is nothing asynchronous about this code apart from the artificial promises slapped onto it. It *only* works because all the events are emitted **synchronously**. There is absolutely nothing gained over `async function split(string) { return string.split(' '); }` or even just `function split(string) { return Promise.resolve(string.split(' ')); }`. – Bergi Aug 31 '20 at 07:22
  • @Bergi Thanks for the answer it is very educational and includes code but where are the events in that? the point is to use n events to do n things about a variable or parameters and return a value from the last event "How to return value from a syncronous function from asyncronous function invoqued from event emitter?" – LT-Sites Aug 31 '20 at 20:51
  • 1
    There are no events in it, that's the whole point. You should not use them, all they do is make your code more complicated. Your synchronously emitted events don't even make anything asynchronous. – Bergi Aug 31 '20 at 21:04