Jaka jest różnica między wartością zwracaną lub Promise.resolve odtąd ()


314

Jaka jest różnica pomiędzy:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return "bbb";
  })
  .then(function(result) {
    console.log(result);
  });

i to:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return Promise.resolve("bbb");
  })
  .then(function(result) {
    console.log(result);
  });

Pytam, gdy dostaję inne zachowanie Używanie usługi Angular i $ http z łańcuchem .then (). Trochę za dużo kodu, stąd pierwszy przykład powyżej.


1
Jakie widzisz „inne zachowanie”? Oba przykłady powinny działać i zachowywać się mniej więcej tak samo. Promise.resolve()W drugim przykładzie nie jest konieczne.
JLRishe,

4
@pixelbits Nie ma nic złego w zwróceniu obietnicy od thenopiekuna, w rzeczywistości jest to kluczowy aspekt specyfikacji obietnic, że możesz to zrobić.

Zauważ, że działa to z dowolnie zagnieżdżonymi thens - termin „inne języki” oznacza, że thenjest to zarówno a, jak mapi a flatMap.
Benjamin Gruenbaum

1
w wierszu 2 dlaczego musisz wywoływać res („aaa”), dlaczego nie możesz zwrócić „aaa” być wystarczające, a obietnica wyłapuje ją dla resol () w ten sam sposób, w jaki wychwytuje wyjątki dla odrzucenia ()?
Sam Liddicott,

1
@SamLiddicott ma to samo pytanie, a kopalnie są nieco bardziej skomplikowane: new Promise((res, rej) => { return fetch('//google.com').then(() => { return "haha"; }) }).then((result) => alert(result));ten kod po prostu zawiesi się (nie zostanie rozwiązany na zawsze). Ale jeśli zmienię return "haha";na, return res("haha");to zadziała i ostrzeże „haha”. Czy funkcja fetch (). Then () nie zawijała już słowa „haha” w obietnicę?
Shaung Cheng

Odpowiedzi:


138

Zasada jest taka, że ​​jeśli funkcja w thenmodule obsługi zwraca wartość, obietnica rozwiązuje / odrzuca tę wartość, a jeśli funkcja zwraca obietnicę, co się dzieje, następna thenklauzula będzie thenklauzulą obietnicy zwróconej przez funkcję , więc w tym przypadku pierwszy przykład przechodzi przez normalną sekwencję thensi wypisuje wartości, jak można się spodziewać, w drugim przykładzie obiekt obietnicy, który jest zwracany, gdy to robisz Promise.resolve("bbb"), to ten, thenktóry jest wywoływany podczas łączenia (dla wszystkich zamiarów i celów). Sposób, w jaki to działa, opisano bardziej szczegółowo poniżej.

Cytowanie ze specyfikacji Promises / A +:

Procedura rozstrzygania obietnicy jest operacją abstrakcyjną, przyjmującą jako dane wejściowe obietnicę i wartość, którą oznaczamy jako [[Resolve]](promise, x). Jeśli xjest to niemożliwe, próbuje sprawić, aby obietnica przyjęła stanx , przy założeniu, że x zachowuje się przynajmniej trochę jak obietnica . W przeciwnym razie spełnia obietnicę z wartością x.

Takie traktowanie elementów niemożliwych pozwala na współdziałanie implementacji obietnic, o ile ujawniają one wówczas metodę zgodną z obietnicami / A +. Umożliwia także implementacjom Promises / A + „asymilację” niezgodnych implementacji za pomocą rozsądnych metod.

Kluczową rzeczą, którą należy tutaj zauważyć, jest ta linia:

jeśli xjest to obietnica, przyjmij jej stan [3.4]

link: https://promisesaplus.com/#point-49


4
„Adopt its state” to zwięzły i użyteczny sposób wyrażenia zachowania, gdy przewodnik thenzwróci obietnicę. +1 za odniesienie do specyfikacji.

69
Właściwie - istotną częścią specyfikacji tutaj jest fakt, że [[Resolve]]jest wywoływany zarówno w thenables, jak i wartościach, więc zasadniczo otacza wartość obietnicą, więc return "aaa"jest taki sam return Promise.resolve("aaa")i return Promise.resolve("aaa")jest taki sam jak return Promise.resolve(Promise.resolve("aaa"))- ponieważ rozdzielczość jest idempotentna, nazywając ją wartością więcej niż raz ma ten sam wynik.
Benjamin Gruenbaum

8
@Benjamin Gruenbaum, czy to oznacza, że ​​zwrot jest możliwy "aaa"i return Promise.resolve("aaa")jest wymienny thenwe wszystkich przypadkach?
CSnerd,

9
Tak, to dokładnie to oznacza.
Benjamin Gruenbaum,

118

Mówiąc najprościej, wewnątrz thenfunkcji modułu obsługi:

A) Kiedy xjest wartością (liczba, ciąg itp.):

  1. return x jest równa return Promise.resolve(x)
  2. throw x jest równa return Promise.reject(x)

B) Kiedy xobietnica jest już rozliczona (nie jest już w toku):

  1. return xjest równoważne return Promise.resolve(x), jeśli obietnica została już rozwiązana.
  2. return xjest równoważne return Promise.reject(x), jeśli obietnica została już odrzucona.

C) Kiedy xnadchodzi obietnica:

  1. return xzwróci oczekującą Obietnicę i zostanie oceniona na podstawie kolejnej then.

Przeczytaj więcej na ten temat w dokumentach Promise.prototype.then () .


92

Oba twoje przykłady powinny zachowywać się prawie tak samo.

Wartość zwrócona w then()module obsługi staje się wartością rozdzielczości obietnicy zwróconej z tej wartości then(). Jeśli wartość zwrócona w .then obietnicy jest obietnicą, zwrócona przez nią obietnica then()„przyjmie stan” tej obietnicy i rozwiąże / odrzuci tak, jak robi to obietnica zwrócona.

W pierwszym przykładzie zwracasz "bbb"w pierwszym then()module obsługi, więc "bbb"jest on przekazywany do następnego modułu then()obsługi.

W drugim przykładzie zwracana jest obietnica, która jest natychmiast rozpatrywana za pomocą wartości "bbb", więc "bbb"jest przekazywana do następnego modułu then()obsługi. ( Promise.resolve()Tutaj jest obce).

Wynik jest taki sam.

Jeśli możesz pokazać nam przykład, który faktycznie wykazuje inne zachowanie, możemy powiedzieć, dlaczego tak się dzieje.


1
Niezła odpowiedź! Co z Promise.resolve();vs return;?
FabianTe

2
@FabianTe Te również miałyby ten sam efekt, z wyjątkiem z undefinedzamiast "bbb".
JLRishe

51

Masz już dobrą formalną odpowiedź. Pomyślałem, że powinienem dodać krótki.

Następujące rzeczy są identyczne z obietnicami / obietnicami A + :

  • Dzwonienie Promise.resolve(w twoim przypadku Angular to jest $q.when)
  • Wywoływanie konstruktora obietnicy i rozstrzyganie w jego resolverie. W twoim przypadku to new $q.
  • Zwracanie wartości z thenwywołania zwrotnego.
  • Wywołanie Promise.all w tablicy z wartością, a następnie wyodrębnij tę wartość.

Zatem poniższe są identyczne dla obietnicy lub zwykłej wartości X:

Promise.resolve(x);
new Promise(function(resolve, reject){ resolve(x); });
Promise.resolve().then(function(){ return x; });
Promise.all([x]).then(function(arr){ return arr[0]; });

I nie jest zaskoczeniem, że specyfikacja obietnic oparta jest na procedurze rozwiązywania obietnic, która umożliwia łatwą współpracę między bibliotekami (np. $ Q i natywnymi obietnicami) i ogólnie ułatwia życie. Ilekroć może dojść do rozwiązania obietnicy, pojawia się rozwiązanie zapewniające ogólną spójność.


czy mogę zapytać o co w tym wszystkim chodzi Promise.resolve().then(function(){ return x; });? Znalazłem wyciętego robiącego coś podobnego (nazywało się to funkcją wewnątrz thenbloku). Myślałem, że to mniej więcej tak, jak zrobić przerwę, ale jest to trochę szybsze. jsben.ch/HIfDo
Sampgun

Nie ma sensu, że jest taki sam jak Promise.resolve (x) w 99,99% przypadków. (0,001% jest to, że jesteśmy w withbloku nad obiektem lub serwerem proxy z xakcesorem właściwości, który zgłasza wyjątek. W takim przypadku Promise.resolve (x) spowodowałoby zgłoszony błąd, ale Promise.resolve().then(function(){ return x; });byłby odrzuconą obietnicą, ponieważ błąd został zgłoszony in a then).
Benjamin Gruenbaum

połączyłeś pusty blitz lub nie uratowałeś. W każdym razie nie mówiłem o różnicach między stwierdzeniami. Mówiłem dokładnie o tym, co napisałem. Wystarczy, aby być bardziej jasne, to jest fragment mówiłam o: if (validator) { Promise.resolve().then(() => { this._cdRef.markForCheck(); }); }. Tutaj obietnica nie jest przypisana, więc po co? Przekroczenie czasu miałoby (mniej więcej) ten sam efekt, czy nie?
Sampgun

1
Wykonuje połączenie asynchronicznie po wystąpieniu całego kodu synchronicznego, ale przed wystąpieniem jakiegokolwiek wejścia / wyjścia. To się nazywa „semantyka microtick”.
Benjamin Gruenbaum

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.