Promise.resolve vs nouvelle promesse (résoudre)

94

J'utilise bluebird et je vois deux façons de résoudre les fonctions synchrones dans une promesse, mais je n'obtiens pas les différences entre les deux. Il semble que le stacktrace soit un peu différent, donc ils ne sont pas seulement un alias, non?

Alors, quelle est la méthode préférée?

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);
}
Pipo
la source
3
Promise.resolveest juste du sucre.
Qantas 94 Heavy
1
Réponse courte - pas de différence d'utilisation. Juste du sucre.
Pinal
@Pinal Qu'est-ce que le "sucre"?
doubleOrt
5
@Taureau. Le sucre syntaxique est une syntaxe conçue pour rendre les choses plus faciles à lire ou à exprimer. voir: wikipedia .
Wyck

Réponses:

82

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 de ne pas être lancées de manière synchrone car elles pourraient être lancées de manière asynchrone. Afin d'éviter des résultats inattendus et des conditions de course, les lancers sont généralement convertis en rejets retournés.

Dans cet esprit, lorsque la spécification a été créée, le constructeur de promesse est sécurisé.

Et si someObjectc'est undefined?

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

Bluebird l'a vu et Petka a ajouté Promise.methodpour résoudre ce problème afin que vous puissiez continuer à utiliser les valeurs de retour. Donc, la façon correcte et la plus simple d'écrire ceci dans Bluebird n'est en fait ni l'un ni l'autre - c'est:

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

Promise.method convertira les lancers en rejets et les retours en résolutions pour vous. C'est le moyen le plus sûr de le faire et il assimile les thencapacités via des valeurs de retour afin que cela fonctionne même s'il someObjects'agit en fait d'une promesse elle-même.

En général, il Promise.resolveest utilisé pour transformer des objets et des promesses étrangères (alorsables) en promesses. C'est son cas d'utilisation.

Benjamin Gruenbaum
la source
"Les fonctions de retour de promesse devraient généralement avoir la garantie qu'elles ne devraient pas être lancées de manière synchrone car elles pourraient être lancées de manière asynchrone". Pourriez-vous expliquer pourquoi les fonctions doivent être synchrones ou asynchrones, mais pas les deux? Actuellement j'apprécie Promise.resolve (), iriez-vous jusqu'à dire que l'utilisation Promise.resolve()est un anti-pattern?
Ashley Coolman
2
@AshleyCoolman voir blog.izs.me/post/59142742143/designing-apis-for-asynchrony - une méthode qui se comporte parfois de manière asynchrone devrait toujours le faire pour des raisons de cohérence.
Benjamin Gruenbaum
Est-ce que Promise.resolve()créer une nouvelle instance de Promisede la même manière que l'utilisation new? Sinon, return Promise.resolve(yourCode)serait plus rapide et éviterait les lancers synchrones.
Steven Vachon le
1
Je me sens mal, j'utilise "Promise.resolve (). Then (function () {/ * case qui peut générer une erreur * /}). Then ..." pour être sûr que l'erreur devienne une promesse rejetée ... Je vais regarder plus dans le "Promise.method"
Polopollo
1
@Polopollo ou Promise.coroutinece qui est encore plus utile.
Benjamin Gruenbaum
16

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

Si someObjectest a Promise, new Promise(resolve)cela coûterait deux ticks supplémentaires.


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 de code afficherait d'abord «tick 3». Pourquoi?

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

  • Mais new Promise(resolve => resolve(value))renverrait une nouvelle promesse qui s'est verrouillée pour suivre la valuepromesse. 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' tick 1 .thenappel serait lancé en premier.


Références:

Edvard Chen
la source