Async: Настройка обработчиков событий с использованием Async

Созданный на 25 окт. 2016  ·  4Комментарии  ·  Источник: caolan/async

У меня проблемы с использованием async в одном из моих интеграционных тестов, который включает обработчики событий. Проблема в том, что обработчик событий должен быть настроен (со ссылкой на обратный вызов, предоставляемый асинхронно) до того, как событие будет отправлено. Однако код обработчика событий требует немедленного дополнительного обратного вызова.

Вот упрощенный пример, показывающий проблему:

async.auto({
  // This needs to run first, but it will finish second
  event: [(next) => {
    emitter.once('awesome', next);
  }],

  // This needs to finish near the end
  checkResults: ['event', (results, next) => {
    assert(results.event.status == 200);
    assert(results.event.msg == 'cool');

    // Do other async stuff...
    somethingAsync(next);
  }],

  // This has to start second, but before the first one finishes
  emit: ['event', (results, next) => {
    event.emit('awesome', {msg: 'cool'}, next);
  }],

  checkEmit: ['emit', (results, next) => {
    // some sort of check that can be async
  },
], done);

event должен начинаться первым, но не завершится, пока не появится emit . emit нужно подождать, пока event запустится, но не завершится (или просто настроить обработчик). Таким образом, это не закончится.

Есть ли способ сделать это с помощью текущей библиотеки async? (в чистом виде)

Вот решение, которое я хотел бы, предполагая, что это может быть реализовано в async

async.auto({
  listen: [(next, done) => {
    client.on(done);
    return next();
  },

  ...
}, callback);

Я мог бы использовать параллельный запуск, выполняя эмиттеры и слушатели (которых может быть несколько в тесте) как массив задач. Взять результаты и запустить проверки как вторую часть. Однако технически параллелизм не требуется для запуска задач по порядку (хотя, скорее всего, так и будет). Кроме того, код становится менее плоским, особенно в более сложных настройках.

question

Самый полезный комментарий

Кстати, я думаю, что это самый безумный вариант использования авто, который я видел: building_construction:

Все 4 Комментарий

Привет @Saevon , спасибо за вопрос!

Быстрый и понятный способ сделать это:

async.auto({
    // This needs to finish near the end
  checkResults: [(next) => {
    return next(null, (results, next) => {
      assert(results.event.status == 200);
      assert(results.event.msg == 'cool');

      // Do other async stuff...
      // somethingAsync(next);
    });
  }],

  // This needs to run first, but it will finish second
  event: ['checkResults', (handler, next) => {
    emitter.once('awesome', handler.checkResults);
    return next();
  }],

  // This has to start second, but before the first one finishes
  emit: ['event', (results, next) => {
    // Should this be emitter.emit instead of event.emit?
    event.emit('awesome', {msg: 'cool'}, next);
  }],

  checkEmit: ['emit', (results, next) => {
    // the results of `checkResults` will be in `results.emit`
    // as the handler on 'awesome' was passed the `next`
    // callback from `emit`

    // some sort of check that can be async
    yourChecks(next);
  }]
}, function done(err) {
    // everything finished running, unless `err` !== `null`
});

По сути, вы просто меняете местами зависимости event и checkResults , что на самом деле может быть немного чище, поскольку event зависит от обработчика в checkResults . checkResults теперь просто передает обработчик event .

Порядок выполнения будет:
checkResults --> event --> emit --> handler (passed to event from checkResults) --> checkEmit --> done .

Дайте мне знать, если что-то неясно.

да, это решает проблему. Спасибо!

Кстати, я думаю, что это самый безумный вариант использования авто, который я видел: building_construction:

Согласовано. Обычно асинхронные обратные вызовы и эмиттеры событий плохо сочетаются ...

Была ли эта страница полезной?
0 / 5 - 0 рейтинги