Async: Configurando Manipuladores de Eventos usando Async

Criado em 25 out. 2016  ·  4Comentários  ·  Fonte: caolan/async

Estou tendo problemas para usar async em um dos meus testes de integração que envolve manipuladores de eventos. O problema é que o manipulador de eventos precisa ser configurado (com uma referência a um retorno de chamada fornecido assíncrono) antes que o evento seja emitido. No entanto, o código do manipulador de eventos precisa de um retorno de chamada extra imediatamente.

Aqui está um exemplo simplificado mostrando o problema:

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 tem que começar primeiro, mas não terminará até que emit ocorra. emit precisa esperar event para começar, mas não terminar (também conhecido como apenas configurar o manipulador). Portanto, isso não vai acabar.

Existe uma maneira de fazer isso com a biblioteca assíncrona atual? (de maneira limpa)

Aqui está uma solução que eu gostaria, supondo que isso pudesse ser implementado de forma assíncrona

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

  ...
}, callback);

Eu poderia usar paralelo, executando os emissores e os ouvintes (dos quais podem haver vários em um teste) como uma série de tarefas. Pegando os resultados e executando as verificações como uma segunda parte. No entanto, o paralelismo técnico não é necessário para iniciar as tarefas em ordem (embora provavelmente o faça). Além disso, o código se torna menos simples, especialmente em configurações mais complicadas.

question

Comentários muito úteis

Acho que é o caso de uso de automóveis mais louco que já vi: building_construction:

Todos 4 comentários

Olá @Saevon , obrigado pela pergunta!

Uma maneira rápida e limpa de fazer isso seria:

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`
});

Essencialmente, você está apenas trocando a dependência event e checkResults , que na verdade pode ser um pouco mais limpa, já que event depende do manipulador em checkResults . checkResults agora está apenas passando o manipulador para event .

A ordem de execução seria:
checkResults --> event --> emit --> handler (passed to event from checkResults) --> checkEmit --> done .

Avise-me se houver alguma dúvida.

sim, isso resolve o problema. Obrigado!

Acho que é o caso de uso de automóveis mais louco que já vi: building_construction:

Concordou. Normalmente, callbacks assíncronos e emissores de eventos não combinam bem ...

Esta página foi útil?
0 / 5 - 0 avaliações