web-dev-qa-db-fra.com

ES6 promet un rappel établi?

Je souhaite exécuter la même action, que ma promesse soit résolue avec succès ou non. Je ne veux pas lier la même fonction aux deux arguments de .then. N'y a-t-il pas un .always comme jQuery? Si non, comment puis-je y parvenir?

42
mpen

N'y a-t-il pas un .always comme jQuery?

Non, il n'y a pas (encore) . Bien qu'il y ait une proposition active , alors peut-être ES2018.

Si non, comment puis-je y parvenir?

Vous pouvez implémenter vous-même la méthode finally comme ceci:

Promise.prototype.finally = function(cb) {
    const res = () => this
    const fin = () => Promise.resolve(cb()).then(res)
    return this.then(fin, fin);
};

ou plus largement, en passant des informations de résolution au rappel:

Promise.prototype.finally = function(cb) {
    const res = () => this
    return this.then(value =>
        Promise.resolve(cb({state:"fulfilled", value})).then(res)
    , reason =>
        Promise.resolve(cb({state:"rejected", reason})).then(res)
    );
};

Les deux assurent que la résolution d'origine est maintenue (lorsqu'il n'y a pas d'exception dans le rappel) et que des promesses sont attendues.

31
Bergi

Si vous ne pouvez pas/ne pouvez pas mettre à jour le prototype, voici comment procéder:

executeMyPromise()
.then(function(res){ return {res: res}; })
.catch(function(err){ return {err: err}; })
.then(function(data) {
    // do finally stuff
    if (data.err) {
        throw data.err;
    }
    return data.res;
}).catch(function(err) {
    // handle error
});
3
user2426679

Voici mon implémentation de .finally ().

Promise.prototype.finally = function(cb) {
   return this.then(v=>Promise.resolve(cb(v)),
                    v=>Promise.reject(cb(v)));
};

Je l'ai testé:

(new Promise((resolve,reject)=>{resolve(5);})).finally(x=>console.log(x));  //5

(new Promise((resolve,reject)=>{reject(6);})).finally(x=>console.log(x));  //6

(new Promise((resolve,reject)=>{reject(7);}))
.then(x=>x,y=>y)
.catch(x=>{throw "error";}) 
.finally(x=>{console.log(x); throw "error"; return x;})  // 7
.then(x=>console.log(x),y=>console.log('e'));  //e
// Uncaught (in promise) undefined
1
Chong Lip Phang

Résumé:

Nous avons également maintenant accès à Promise.prototype.finally(). C'est une fonction qui peut être ajoutée à la chaîne de promesse en tant que dernier élément pour effectuer un nettoyage. cela fonctionne de la manière suivante par rapport à Promise.then et Promise.catch:

  • Promise.then only est appelé lorsque la promesse est résolue (si vous ne la mettez que comme fonction de rappel du premier argument)
  • Promise.catch only est appelé lorsque la promesse est rejetée
  • Promise.finally always est appelé quand une promesse est remplie, donc les deux quand la promesse est rejetée ou résolue. 

Exemple:

let Prom = new Promise((res, rej) => {
  let random = Math.random();
  
  if (random > 0.5) {
    res(1);
  } else {
    rej('Error occured')
  }

  
});


Prom.then((val) => {
  console.log(val);
  return val * 10;
}).catch((err) => {
  console.log(err);
}).finally(() => {
  console.log('finally executed');
})

Dans l'exemple ci-dessus, nous pouvons observer que finally est toujours exécuté, que la promesse soit résolue ou rejetée. Non pas que finally devrait idéalement toujours être à la fin de la chaîne de promesse pour effectuer un nettoyage qui devrait être exécuté quel que soit le résultat de Promise. 

L'utilisation de finally présente l'avantage d'éviter la duplication de code, car celle-ci est exécutée pour une promesse résolue ou rejetée. Sinon, nous devrions utiliser des hacks comme:

.then(onfullfilled, onfullfilled)

ou 

.then(onfullfilled)
.catch(onfullfilled)

Notez que maintenant nous devons définir la fonction onfullfilled en tant que fonction nommée en dehors du gestionnaire de promesses lui-même (ou passer 2 copies de fonctions anonymes qui sont encore moins élégantes). Promise.finally résout ce problème pour nous.

1

Pour prolonger la réponse Bergi.

Renvoyer Promise.reject () dans le gestionnaire de captures empêchera la finnalisation de "then" à appeler.

Donc, si vous allez gérer une erreur de promesse plus de 2 fois, vous devez utiliser un passe-partout comme ceci:

return myPromise()
.then(() => ... )
.catch((error) => {
  ...
  myFinnaly();
  return Promise.reject(error);
})
.then(() => myFinnaly());
0
Nikita

Pas besoin d'introduire de nouveaux concepts

const promise = new Promise((resolve, reject) => {
  /*some code here*/
});

promise.then(() => {
  /* execute success code */
}, () => {
  /* execute failure code here */
}).then(() => {}, () => {}).then(() => {
  /* finally code here */
});
0
Luis Banegas Saybe