Promise.resolve a nowa obietnica (rozwiązanie)

98

Używam bluebird i widzę dwa sposoby przekształcania funkcji synchronicznych w obietnicę, ale nie widzę różnic między nimi. Wygląda na to, że ślad stosu jest nieco inny, więc nie są one tylko znakami alias, prawda?

Więc jaki jest preferowany sposób?

Sposób A

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

Droga B

function someFunction(someObject) {
  someObject.resolved = true;
  return Promise.resolve(someObject);
}
Pipo
źródło
3
Promise.resolveto tylko cukier.
Qantas 94 Heavy
1
Krótka odpowiedź - bez różnicy w użyciu. Tylko cukier.
Pinal
@Pinal Co to jest „cukier”?
doubleOrt
6
@Byk. Cukier syntaktyczny to składnia zaprojektowana w celu ułatwienia czytania lub wyrażania. zobacz: wikipedia .
Wyck

Odpowiedzi:

86

W przeciwieństwie do obu odpowiedzi w komentarzach - jest różnica.

Podczas

Promise.resolve(x);

jest w zasadzie taki sam jak

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

jest subtelność.

Funkcje zwracające obietnicę powinny generalnie mieć gwarancję, że nie powinny wyrzucać synchronicznie, ponieważ mogą wyrzucać asynchronicznie. Aby zapobiec nieoczekiwanym wynikom i warunkom wyścigu - rzuty są zwykle konwertowane na zwrócone odrzucenia.

Mając to na uwadze - kiedy specyfikacja została stworzona, obiecujący konstruktor jest bezpieczny.

A jeśli someObjecttak undefined?

  • Sposób A zwraca odrzuconą obietnicę.
  • Droga B rzuca synchronicznie.

Bluebird zauważył to i Petka dodał, Promise.methodaby rozwiązać ten problem, abyś mógł nadal używać zwracanych wartości. Tak więc poprawny i najłatwiejszy sposób zapisania tego w Bluebird to w rzeczywistości żadne z nich - to jest:

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

Promise.method zamieni rzuty na odrzucenia i wróci do rozstrzygnięć za Ciebie. Jest to najbardziej bezpieczny sposób, aby to zrobić, i asymiluje thenables poprzez zwracane wartości, więc zadziała, nawet jeśli someObjectjest w rzeczywistości obietnicą.

Ogólnie Promise.resolvejest używany do odlewania przedmiotów i obcych obietnic (dóbr) na obietnice. To jest jego przypadek użycia.

Benjamin Gruenbaum
źródło
„Funkcje zwracające obietnicę powinny generalnie mieć gwarancję, że nie powinny wyrzucać synchronicznie, ponieważ mogą wyrzucać asynchronicznie”. Czy mógłbyś rozwinąć, dlaczego funkcje powinny być synchroniczne lub asynchroniczne, ale nie oba? Obecnie lubię Promise.resolve (), czy posunąłbyś się nawet do stwierdzenia, że ​​używanie Promise.resolve()jest anty-wzorcem?
Ashley Coolman
2
@AshleyCoolman patrz blog.izs.me/post/59142742143/designing-apis-for-asynchrony - metoda, która czasami zachowuje się asynchronicznie, powinna zawsze robić to dla spójności.
Benjamin Gruenbaum
Czy Promise.resolve()tworzy nową instancję Promisew taki sam sposób, jak przy użyciu new? Jeśli nie, return Promise.resolve(yourCode)byłby szybszy i unikał synchronicznych rzutów.
Steven Vachon
1
Źle się czuję, używam „Promise.resolve (). Then (function () {/ * case that can throw a error * /}). Then ...” by upewnić się, że błąd staje się odrzuconą obietnicą ... Przyjrzę się dokładniej „Promise.method”
Polopollo
1
@Polopollo lub Promise.coroutineco jest jeszcze bardziej przydatne.
Benjamin Gruenbaum
18

Jest jeszcze jedna różnica nie wymieniona w powyższych odpowiedziach lub komentarzach:

Jeśli someObjectjest Promise, new Promise(resolve)kosztowałoby dwa dodatkowe tiki.


Porównaj dwa następujące fragmenty kodu:

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

Drugi fragment wypisuje najpierw „tick 3”. Czemu?

  • Jeśli wartość jest obietnicą, Promise.resolve(value)zwróci wartość dokładnie. Promise.resolve(value) === valuebyłoby prawdą. zobacz MDN

  • Ale new Promise(resolve => resolve(value))zwróci nową obietnicę, która została zablokowana, aby spełnić valueobietnicę. Potrzeba dodatkowego jednego zaznaczenia, aby „zablokować się”.

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

    tick 1 .thenWezwanie byłoby w pierwszej kolejności.


Bibliografia:

edvard chen
źródło