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.
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 ...
Comentários muito úteis
Acho que é o caso de uso de automóveis mais louco que já vi: building_construction: