Могу ли я использовать async/await для ожидания нескольких событий в JavaScript?

Рассмотрим следующий случай:

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


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


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

  api.load();
}

Что я пытаюсь сделать, так это настроить обратные вызовы событий для переменной api внутри асинхронной функции, вызвать функцию api.load(), а затем вернуть событие, которое произошло первым, в данном случае либо eventOne|eventTwo|eventThree

Проблема в том, что этот синтаксис плохой, и этот пример не работает. Я не мог найти способ добиться этого с помощью async/await, и мне пришлось вернуться к таким обещаниям:

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


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


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

    api.load();
  }
}

Итак, мой вопрос: можно ли это сделать с помощью async/await? В любом случае, это можно сделать с помощью нового синтаксиса async/await es7?


person SagiSergeNadir    schedule 02.05.2017    source источник
comment
Одна из проблем заключается в том, что ваши операторы return возвращают свое значение из своих конкретных функций обработчика событий, а не из основной функции waitForEvent.   -  person Will P.    schedule 03.05.2017
comment
Конечно, я это знаю :) спасибо, что указали на это. Я пытаюсь найти способ обойти это.   -  person SagiSergeNadir    schedule 03.05.2017
comment
Я не понимаю, что вы имеете в виду под мне пришлось вернуться к обещаниям. async/await все равно использует промисы? А если api не обещано, нужно использовать конструктор Promise.   -  person Bergi    schedule 03.05.2017
comment
В чем смысл eventOne, eventTwo, eventThree? Это один из них или любое их количество в любом порядке или все 3 в случайном порядке? Я спрашиваю, потому что, возможно, обещания - не лучшая абстракция для вашей проблемы.   -  person Kos    schedule 23.08.2017


Ответы (1)


Поскольку async/await позволяет нам писать асинхронные конструкции синхронно (лексически сверху вниз), на самом деле не существует специального подхода для одновременного выполнения 3 разных строк кода (или, точнее, операторов).

Идеальным API для этого является Promise.race.

Сначала вы конвертируете обратный вызов API в возврат обещания:

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

Затем вы участвуете во всех нужных вам событиях:

const waitForEvent = (api) => {

  const apiPromise = apiPromiseBuilder(api);

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

  api.load();

  return promiseRace;
};

Или используя 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;
};
person nem035    schedule 02.05.2017
comment
это было мое внутреннее чувство и то, чего я боялся. Думал, я бы спросил на stackoverflow, чтобы быть уверенным. Я нахожусь на грани с async/await, если мне придется смешивать его с обещаниями в определенных случаях, я не уверен, что не просто лучше использовать обещания все время и отказаться от async/await на данный момент. Спасибо за исчерпывающий ответ. - person SagiSergeNadir; 03.05.2017
comment
async/await основан на промисах, просто скрывает кое-что под капотом. Вы всегда используете обещания с ним, хотя и не каждый раз явно. Как говорится, каждая ситуация уникальна, делайте то, что вам больше нравится :) - person nem035; 03.05.2017
comment
Кажется, что это не только прячет вещи под капотом, но и накладывает ограничения, например, возвращает только одна переменная и... ну... все ограничение, о котором мой пост. Спасибо за ответ! - person SagiSergeNadir; 03.05.2017