Promise.resolve vs new Promise (Entschlossenheit)

91

Ich verwende Bluebird und sehe zwei Möglichkeiten, um synchrone Funktionen in ein Versprechen aufzulösen, aber ich verstehe die Unterschiede zwischen beiden Möglichkeiten nicht. Es sieht so aus, als ob der Stacktrace ein bisschen anders ist, also sind sie nicht nur ein alias, oder?

Was ist der bevorzugte Weg?

Weg A.

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

Weg B.

function someFunction(someObject) {
  someObject.resolved = true;
  return Promise.resolve(someObject);
}
Pipo
quelle
2
Promise.resolveist nur Zucker.
Qantas 94 Heavy
1
Kurze Antwort - kein Unterschied in der Verwendung. Nur Zucker.
Pinal
@Pinal Was ist "Zucker"?
DoubleOrt
5
@Stier. Syntaktischer Zucker ist eine Syntax, die das Lesen oder Ausdrücken erleichtert. siehe: wikipedia .
Wyck

Antworten:

82

Im Gegensatz zu beiden Antworten in den Kommentaren gibt es einen Unterschied.

Während

Promise.resolve(x);

ist im Grunde das gleiche wie

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

es gibt eine Subtilität.

Versprechende Rückgabefunktionen sollten im Allgemeinen die Garantie haben, dass sie nicht synchron ausgelöst werden, da sie möglicherweise asynchron ausgelöst werden. Um unerwartete Ergebnisse und Rennbedingungen zu vermeiden, werden Würfe normalerweise in zurückgegebene Ablehnungen umgewandelt.

In diesem Sinne ist der Versprechen-Konstruktor bei der Erstellung der Spezifikation sicher.

Was passiert , wenn someObjectist undefined?

  • Weg A gibt ein abgelehntes Versprechen zurück.
  • Weg B wirft synchron.

Bluebird hat dies Promise.methoderkannt und Petka hat hinzugefügt , um dieses Problem zu beheben, damit Sie weiterhin Rückgabewerte verwenden können. Der richtige und einfachste Weg, dies in Bluebird zu schreiben, ist eigentlich keiner - es ist:

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

Promise.method konvertiert Würfe in Ablehnungen und kehrt für Sie in Auflösungen zurück. Es ist der sicherste Weg, dies zu tun, und es assimiliertthen Fähigkeiten durch Rückgabewerte, so dass es funktionieren würde, selbst wenn someObjectes tatsächlich ein Versprechen selbst ist.

Promise.resolveWird im Allgemeinen verwendet, um Objekte und ausländische Versprechen (thenables) in Versprechen umzuwandeln. Das ist der Anwendungsfall.

Benjamin Gruenbaum
quelle
"Versprechende Rückgabefunktionen sollten im Allgemeinen die Garantie haben, dass sie nicht synchron ausgelöst werden, da sie möglicherweise asynchron ausgelöst werden." Können Sie erläutern, warum Funktionen entweder synchron oder asynchron sein sollten, aber nicht beide? Momentan gefällt mir Promise.resolve (). Würden Sie so weit gehen zu sagen, dass die Verwendung Promise.resolve()ein Anti-Pattern ist?
Ashley Coolman
2
@AshleyCoolman siehe blog.izs.me/post/59142742143/designing-apis-for-asynchrony - eine Methode, die sich manchmal asynchron verhält, sollte dies aus Gründen der Konsistenz immer tun.
Benjamin Gruenbaum
Erstellt Promise.resolve()eine neue Instanz Promiseauf die gleiche Weise wie mit new? Wenn nicht, return Promise.resolve(yourCode)wäre schneller und vermeiden Sie synchrone Würfe.
Steven Vachon
1
Ich fühle mich schlecht, ich benutze "Promise.resolve (). Then (function () {/ * case, der einen Fehler auslösen kann * /}). Then ...", um sicherzugehen, dass der Fehler zu einem abgelehnten Versprechen wird ... Ich werde mehr in die "Promise.method"
Polopollo
1
@Polopollo oder Promise.coroutinewas noch nützlicher ist.
Benjamin Gruenbaum
16

Es gibt einen weiteren Unterschied, der in den obigen Antworten oder Kommentaren nicht erwähnt wird:

Wenn someObjectist ein Promise, new Promise(resolve)würde zwei zusätzliche Tick kosten.


Vergleichen Sie zwei folgende Codeausschnitte:

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

Das zweite Snippet würde zuerst "Tick 3" drucken. Warum?

  • Wenn der Wert ein Versprechen ist, Promise.resolve(value)würde er den Wert genau zurückgeben. Promise.resolve(value) === valuewäre wahr. siehe MDN

  • Aber new Promise(resolve => resolve(value))würde ein neues Versprechen zurück , die in gesperrt hat die folgen valueVersprechen. Es wird ein zusätzliches Häkchen benötigt, um das "Einrasten" durchzuführen.

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

    Der tick 1 .thenAnruf würde zuerst ausgeführt.


Verweise:

edvard chen
quelle