6

Consider the following case:

const waitForEvent = async (api) => {
  api.on('eventOne', () => {
    return 'eventOne';
  })


  api.on('eventTwo', () => {
    return 'eventTwo';
  })


  api.on('eventThree', () => {
    return 'eventThree';
  })

  api.load();
}

What I am trying to do is setup event callbacks on the api variable inside the async function, trigger the api.load() function, and then return the event that happened first, in this case either eventOne|eventTwo|eventThree

Problem is, this syntax is bad, and this example does not work. I couldn't find any way to achieve this using async/await and had to revert to promises like this:

const waitForEvent = (api) => {
  return new Promise(resolve) => {
    api.on('eventOne', () => {
      resolve('eventOne');
    })


    api.on('eventTwo', () => {
      resolve('eventTwo');
    })


    api.on('eventThree', () => {
      resolve('eventThree');
    })

    api.load();
  }
}

So my question is, can this be accomplished using async/await? Anyway this can be done using the new async/await es7 syntax?

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
aaa
  • 601
  • 6
  • 13
  • One problem is that your `return` statements are returning their value from their specific event handler functions, not the main `waitForEvent` function – Will P. May 02 '17 at 21:03
  • Of course, I know that :) thanks for pointing that out. I am trying to figure a way to go around that. – aaa May 02 '17 at 21:07
  • I don't get what you mean by "*I had to revert to promises*". `async`/`await` uses promises anyway? And if `api` is not promisified, you need to use the `Promise` constructor. – Bergi May 02 '17 at 21:55
  • What's the meaning of eventOne, eventTwo, eventThree? Is it "one of them" or "any number of them in any order" or "all 3 in a random order"? I'm asking because maybe promises are not the best abstraction for your problem. – Kos Aug 23 '17 at 09:19

1 Answers1

9

Since async/await allows us to write async constructs in a synchronous-looking manner (lexical top-down), there isn't really a specific approach to execute 3 different lines of code (or more accurately, statements) simultaneously.

The ideal api for this is the Promise.race.

First you convert your api callback into returning a promise:

const apiPromiseBuilder = (api) => (eventName) => new Promise(resolve => api.on(eventName, () => {
  resolve(eventName);
}));

Then you race all the events you need:

const waitForEvent = (api) => {

  const apiPromise = apiPromiseBuilder(api);

  const promiseRace = Promise.race([
    apiPromise('eventOne'),
    apiPromise('eventTwo'),
    apiPromise('eventThree')
  ]);

  api.load();

  return promiseRace;
};

Or using async/await:

async function waitForEvent(api) {

  const apiPromise = apiPromiseBuilder(api);

  const promiseRace = Promise.race([
    apiPromise('eventOne'),
    apiPromise('eventTwo'),
    apiPromise('eventThree')
  ]);

  api.load();

  const firstResult = await promiseRace;

  return firstResult;
};
nem035
  • 34,790
  • 6
  • 87
  • 99
  • that was my gut feeling and what I was afraid of. Thought I would ask on stackoverflow to be sure. I am on the fence with async/await, if I have to mix it with promises in certain cases, I am not sure it's not just better to use promises all along and forsake async/await for now. Thanks for the thorough answer. – aaa May 02 '17 at 21:15
  • 1
    async/await is promise-based, just hides some the stuff under the hood. You always use promises with it, although not explicitly every time. That being said, every situation is unique, do what you like better :) – nem035 May 02 '17 at 21:18
  • It seems that it's not only hiding stuff under the hood, but also imposes limitations like one variable returns only and.. well.. the entire limitation that my post is about. Thanks for the feedback! – aaa May 02 '17 at 21:22