web-dev-qa-db-fra.com

Promise.resolve vs new Promise (résoudre)

J'utilise bluebird et je vois deux façons de résoudre les fonctions synchrones en une promesse, mais je ne comprends pas les différences entre les deux. Il semble que le stacktrace soit un peu différent, donc ce n'est pas qu'un alias, n'est-ce pas?

Alors, quel est le moyen préféré?

voie A

function someFunction(someObject) {
  return new Promise(function(resolve) {
    someObject.resolved = true;
    resolve(someObject);
  });
}

voie B

function someFunction(someObject) {
  someObject.resolved = true;
  return Promise.resolve(someObject);
}
75
Pipo

Contrairement aux deux réponses dans les commentaires, il y a une différence.

Tandis que

Promise.resolve(x);

est fondamentalement le même que

new Promise(function(r){ r(x); });

il y a une subtilité.

Les fonctions de retour de promesse devraient généralement avoir la garantie qu'elles ne lanceraient pas de manière synchrone car elles pourraient lancer de manière asynchrone. Afin d'éviter des résultats et des situations de compétition inattendus, les lancers sont généralement convertis en rejets renvoyés.

Dans cet esprit, lors de la création de la spécification, le constructeur de promesse est protégé.

Et si someObject est undefined?

  • La voie A renvoie une promesse refusée.
  • La voie B jette de manière synchrone.

Bluebird a vu cela, et Petka a ajouté Promise.method pour résoudre ce problème afin que vous puissiez continuer à utiliser les valeurs de retour. Donc, la manière la plus correcte et la plus simple d’écrire cela dans Bluebird n’est en réalité ni l’une, ni l’autre:

var someFunction = Promise.method(function someFunction(someObject){
    someObject.resolved = true;
    return someObject;
});

Promise.method convertira les jets en rejets et en résout les résolutions pour vous. C'est le moyen le plus sûr de le faire. Il assimile thenable à travers les valeurs de retour afin qu'il fonctionne même si someObject est en fait une promesse en soi.

En général, Promise.resolve est utilisé pour lancer des objets et des promesses étrangères (thenables) à des promesses. C'est son cas d'utilisation.

70

Il y a une autre différence non mentionnée dans les réponses ou commentaires ci-dessus:

Si someObjectis est en attente Promise, new Promise(resolve) coûterait un tick supplémentaire.


Comparez deux extraits de code suivants:

const p = new Promise(resovle => setTimeout(resovle));

new Promise(resolve => resolve(p)).then(() => {
  console.log("tick 3");
});

p.then(() => {
  console.log("tick 1");
}).then(() => {
  console.log("tick 2");
});
const p = new Promise(resovle => setTimeout(resovle));

Promise.resolve(p).then(() => {
  console.log("tick 3");
});

p.then(() => {
  console.log("tick 1");
}).then(() => {
  console.log("tick 2");
});

Le deuxième extrait serait d'abord "tick 3". Pourquoi?

  • Si la valeur est une promesse, Promise.resolve(value) renverra exactement la valeur. Promise.resolve(value) === value serait vrai. voir MDN

  • Mais new Promise(resolve => resolve(value)) renverrait une nouvelle promesse qui s'est verrouillée pour suivre la promesse value. Il faut une coche supplémentaire pour effectuer le "verrouillage".

    // something like:
    addToMicroTaskQueue(() => {
      p.then(() => {
        /* resolve newly promise */
      })
        // all subsequent .then on newly promise go on from here
        .then(() => {
          console.log("tick 3");
        });
    });
    

    L'appel tick 1.then Sera exécuté en premier.


Les références:

8
edvard chen