J'ai des difficultés à utiliser async dans l'un de mes tests d'intégration impliquant des gestionnaires d'événements. Le problème est que le gestionnaire d'événements doit être configuré (avec une référence à un rappel fourni asynchrone) avant que l'événement ne soit émis. Cependant, le code du gestionnaire d'événements a besoin d'un rappel supplémentaire immédiatement.
Voici un exemple simplifié montrant le problème :
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
doit commencer en premier, mais ne se terminera pas tant que le emit
se produira pas. emit
doit attendre que event
démarre, mais ne se termine pas (il suffit de configurer le gestionnaire). Donc ça ne finira pas.
Existe-t-il un moyen de le faire avec la bibliothèque asynchrone actuelle ? (de manière propre)
Voici une solution que j'aimerais, en supposant que cela puisse être implémenté de manière asynchrone
async.auto({
listen: [(next, done) => {
client.on(done);
return next();
},
...
}, callback);
Je pourrais utiliser en parallèle, en exécutant les émetteurs et les auditeurs (dont il peut y en avoir plusieurs dans un test) comme un ensemble de tâches. Prendre les résultats et effectuer les vérifications dans un deuxième temps. Cependant, le parallélisme technique n'est pas nécessaire pour lancer les tâches dans l'ordre (bien qu'il le soit probablement). De plus, le code devient moins plat, en particulier dans les configurations plus compliquées.
Salut @Saevon , merci pour la question !
Une façon rapide et propre de le faire serait :
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`
});
Essentiellement, vous échangez simplement les dépendances event
et checkResults
, ce qui pourrait en fait être un peu plus propre, car event
dépend du gestionnaire dans checkResults
. checkResults
fait que passer le gestionnaire à event
.
L'ordre d'exécution serait :
checkResults --> event --> emit --> handler (passed to event from checkResults) --> checkEmit --> done
.
Faites-moi savoir si quelque chose n'est pas clair.
oui, cela résout le problème. Merci!
Je pense que c'est le cas d'utilisation automatique le plus fou que j'ai vu d'ailleurs :building_construction:
D'accord. Habituellement, les rappels asynchrones et les émetteurs d'événements ne font pas bon ménage...
Commentaire le plus utile
Je pense que c'est le cas d'utilisation automatique le plus fou que j'ai vu d'ailleurs :building_construction: