3
votes

Comment résoudre une promesse différente dans chaque cas de bloc de commutation et transmettre leurs résultats à la même fonction?

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()?


1 commentaires

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


5 Réponses :


3
votes

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


2 commentaires

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



-1
votes

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


1 commentaires

il n'y a aucune raison d'avoir un tableau de promesses alors qu'il ne peut y en avoir qu'une: p



3
votes

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


5 commentaires

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



0
votes

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');


0 commentaires

0
votes

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


0 commentaires