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