Supposons que je veuille exécuter différentes chaînes de promesses dans les différents blocs case
d'un bloc switch
, et finalement renvoyer le résultat au client via res. end ()
, comme ceci:
case 'a': someObj.action_a() .then(result=>{ resValue=result.id; doSomethingElse(); res.end(resValue); }); break; case 'b': someObj.action_b() .then(result=>{ resValue=result.id; doSomethingElse(); res.end(resValue); }); break; default: resValue="default"; doSomethingElse(); res.end(resValue);
Ce qui finit par se passer, c'est que resValue
est renvoyé comme "valeur initiale"
, ce qui a du sens car les fonctions asynchrones dans les blocs case
ne mettent pas à jour resValue
avant que l'exécution n'atteigne res.end ()
. Je pourrais déplacer le code post- switch
dans les résolutions de promesse comme ceci:
app.post('/endpoint',function(req,res){ var reqValue=req.body.value; var resValue="initial value"; switch(reqValue){ case 'a': someObj.action_a() .then(result=>{ resValue=result.id; }); break; case 'b': someObj.action_b() .then(result=>{ resValue=result.id; }); break; default: resValue="default"; } doSomethingElse(); res.end(resValue); });
mais alors il s'agit de dupliquer du code et donc plus difficile à maintenir. Existe-t-il un meilleur moyen pour que ces promesses médiées par switch
aboutissent toutes au même res.end()
?
5 Réponses :
Vous pouvez utiliser une seule variable pour tenir une promesse de la resValue requise comme ceci
app.post('/endpoint',async function(req,res){ let reqValue=req.body.value; let resValue="initial value"; switch(reqValue){ case 'a': resValue = await someObj.action_a().then(result => result.id); break; case 'b': resValue = await someObj.action_b().then(result => result.id); break; default: resValue = "default"; } doSomethingElse(); res.end(resValue); });
ou en utilisant javascript moderne, utilisez async / await
app.post('/endpoint',function(req,res){ let reqValue=req.body.value; let p; switch(reqValue){ case 'a': p = someObj.action_a().then(result => result.id); break; case 'b': p = someObj.action_b().then(result => result.id); break; default: // p has to be a promise, so make it one p = Promise.resolve("default"); } p.then(resValue => { doSomethingElse(); res.end(resValue); }); });
c'est pourquoi copier / coller est une mauvaise chose: p
Je ne suis pas votre accusation @vdegenne - bien sûr, j'ai copié / collé puis changé le code de l'OP
Promise.all
est un outil très pratique pour garder le suivi de toutes les tâches de sous-promesses
const jobqQeue = []; switch(...) { case: '...': { jobqQeue.push( subPromise() ); } case: '...': { jobqQeue.push( subPromise2() ); } default: { jobqQeue.push( defaultOpPromise(); ); } } Promise.all(jobqQeue) .then(results => { ... }) .catch(error => console.error(error));
il n'y a aucune raison d'avoir un tableau de promesses alors qu'il ne peut y en avoir qu'une: p
Si vous pouvez utiliser les nouvelles fonctionnalités de JavaScript, je vous recommande async
et wait
car elles sont faciles à lire et à utiliser, votre code deviendrait ainsi: < pré> XXX
vous ne pouvez pas simplement utiliser await
comme ça - c'est-à-dire que vous avez oublié de montrer que la fonction englobante doit être async
: p ... Si vous pouvez utiliser new fonctionnalités de JavaScript
- OP utilise des fonctions fléchées, pari assez sûr: p
@JaromandaX a intentionnellement omis! car s'il devait utiliser cette syntaxe moderne de JS, il se heurterait certainement à d'autres problèmes dont il a besoin pour apprendre de lui-même. Inutile de dire que j'essayais juste de le diriger vers une solution qui pourrait l'intéresser: p
@JaromandaX OP utilise des fonctions fléchées, pari assez sûr: p
- async
et await
sont ES2017, les fonctions flèches sont ES2015. Ce n'est pas une valeur sûre.
@vdegenne resValue = (wait someObj.action_a ()). id;
refléterait l'intention de la question. Actuellement, vous attribuez result
au lieu de result.id
.
@PatrickRoberts - peu de gens utiliseraient un environnement qui a l'un et pas l'autre - cependant, il y en a qui s'accrochent à des nœuds particulièrement anciens, donc je suppose que c'est un bon point
Peut-être, à la place, pourriez-vous créer une fonction générale qui renvoie des données en fonction du type d'action donné, et y avoir le commutateur
, et utiliser un simple async / await dans votre fonction principale juste pour attendre le résultat que
// Made up function that switches action // based on the type (in this case the timer on the // setTimeout) function doAction(type) { let time; switch(type) { case 'a': time = 1000; break; case 'b': time = 2000; break; case 'c': time = 300; break; } return new Promise(resolve => { setTimeout(() => resolve({ id: `${type}1` }), time); }); } async function main(type) { try { // Pass in the type to the doAction function, // let that decide what to do, and await the promise // to resolve const result = await doAction(type); // Then just console.log or res.send the result const resValue = result.id; console.log(resValue); } catch (e) { console.log(e); } } main('b'); main('a'); main('c');
Voici une option si vous ne pouvez pas utiliser async / await
et que vous devez vous en tenir aux Promises
(Cependant, les ternaires imbriqués peuvent devenir disgracieux si vous avez beaucoup de cas; lisez la suite pour une idée différente):
const actions = { a: () => someObj.action_a(); b: () => someObj.action_b(); // ... n: () => someObj.action_n(); }; app.post('endpoint', function(req, res) { const action = actions[req.body.value]; (action && action().then(({id}) => id) || Promise.resolve('default')) .then(resValue => { doSomethingElse(); res.end(resValue); }); });
Au lieu de cela, supposons que vous stockiez vos actions dans un Object
:
app.post('/endpoint', function(req, res) { const reqValue = req.body.value; (reqValue === 'a' ? someObj.action_a().then(({id}) => id) : reqValue === 'b' ? someObj.action_b.then(({id}) => id) : Promise.resolve('default')) .then(resValue => { doSomethingElse(); res.end(resValue); }); });
traiter ce bloc de code comme synchrone
- moyen dangereux de traiter le code asynchrone - que diriez-vous d'utiliser async await sans le reste: p