Jakie są różnice między odroczeniem, obietnicą i przyszłością w JavaScript?


300

Jakie są różnice między odroczonymi, obietnicami i kontraktami terminowymi?
Czy kryje się za tym ogólnie przyjęta teoria?


11
Nie sądzę, żeby miało to coś wspólnego z jQuery ...
BoltClock


8
Sam ich nie użyłem, ale tutaj jest całkiem niezłe wprowadzenie na wikipedii en.wikipedia.org/wiki/Futures_and_promises . Chociaż nie do końca rozumiem przypadek użycia poprawnie. W języku sterowanym zdarzeniami asynchronicznymi, takim jak javascript. Na pierwszy rzut oka nie widzę, co oferują poza wywołaniami zwrotnymi, może poza czystszym API. Bardzo bym chciał, gdyby ktoś mógł podać przykładowy przypadek użycia i pokazać, w jaki sposób te koncepcje są stosowane i dlaczego wywołania zwrotne byłyby nieefektywnym rozwiązaniem. @duri nie ma to nic wspólnego z jQuery. Czy tag jQuery można usunąć
AshHeskes

2
@ jfriend00 świetny link, prawdopodobnie powinien zostać przerobiony na odpowiedź.
fncomp

Odpowiedzi:


97

W świetle pozornej niechęci do tego, jak próbowałem odpowiedzieć na pytanie OP. Dosłowna odpowiedź brzmi: obietnica jest czymś współdzielonym z innymi przedmiotami, a odroczona powinna być prywatna. Przede wszystkim odroczona (która zasadniczo przedłuża Obietnicę) może rozwiązać się sama, podczas gdy obietnica może nie być w stanie tego zrobić.

Jeśli interesują Cię drobiazgi, sprawdź Promises / A + .


O ile mi wiadomo, nadrzędnym celem jest poprawienie przejrzystości i poluzowanie sprzężenia poprzez ustandaryzowany interfejs. Zobacz sugerowaną lekturę od @ jfriend00:

Zamiast bezpośrednio przekazywać wywołania zwrotne do funkcji, co może prowadzić do ściśle powiązanych interfejsów, użycie obietnic pozwala rozdzielić obawy dotyczące kodu synchronicznego lub asynchronicznego.

Osobiście uważam, że odroczenie jest szczególnie przydatne, gdy zajmujemy się np. Szablonami wypełnionymi żądaniami asynchronicznymi, ładowaniem skryptów zawierających sieci zależności i dostarczaniem opinii użytkowników w celu tworzenia danych w sposób nie blokujący.

Rzeczywiście, porównaj czystej postaci zwrotnej robienia czegoś po załadowaniu CodeMirror w trybie JS asynchronicznie (przeprosiny, nie używałem jQuery w czasie ):

/* assume getScript has signature like: function (path, callback, context) 
   and listens to onload && onreadystatechange */
$(function () {
   getScript('path/to/CodeMirror', getJSMode);

   // onreadystate is not reliable for callback args.
   function getJSMode() {
       getScript('path/to/CodeMirror/mode/javascript/javascript.js', 
           ourAwesomeScript);
   };

   function ourAwesomeScript() {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   };
});

Do sformułowanej wersji obietnic (ponownie przepraszam, nie jestem na bieżąco z jQuery):

/* Assume getScript returns a promise object */
$(function () {
   $.when(
       getScript('path/to/CodeMirror'),
       getScript('path/to/CodeMirror/mode/javascript/javascript.js')
   ).then(function () {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   });
});

Przepraszamy za częściowo pseudo-kod, ale mam nadzieję, że wyjaśnia on nieco ideę. Zasadniczo, zwracając znormalizowaną obietnicę, możesz ją przekazać, umożliwiając w ten sposób wyraźniejsze grupowanie.


10
Chociaż ta odpowiedź może być przydatna, nie odpowiada w rzeczywistości na pytanie: tak zwane odroczenia są albo przyszłością, albo obietnicami, w zależności od wdrożenia.
awdz9nld

@ MartinKällman Masz rację! Od dłuższego czasu nie odwiedzałem tego i nauczyłem się trochę. Poniżej zamieszczę osobną odpowiedź, ale zostawię to, ponieważ wydaje się, że ludzie skorzystali z przykładu użycia.
fncomp

@ MartinKällman, rozważał napisanie nowej odpowiedzi. Myślę jednak, że OP naprawdę chciał wiedzieć, do czego służą Obietnice i Odroczenia. Odpowiedź na jego aktualne pytanie brzmiałaby w przybliżeniu: „odroczeni mogą rozwiązać siebie. AFAIK, teoria obietnic i odroczeń pochodzi z [Functional Reactive Programming | haskell.org/haskellwiki/Functional_Reactive_Programming] , która jest techniką spłaszczania wywołań zwrotnych . ”
fncomp

2
Jest to całkowicie błędne, a twoje przykłady są równie łatwe do wykonania z wywołaniami zwrotnymi. W obietnicach nie chodzi o agregację i odsprzęganie oddzwaniania, ale zapewnienie DSL do pisania kodu asynchronicznego, tak jak zapisywany jest kod synchronizacji. Zwłaszcza fn(callback, errback)nie jest ściślej związany ani mniej przydatny niż fn().then(callback, errback)- ale i tak jest to zły sposób na stosowanie obietnic. Szczególnie nienawidzę $.whenprzykładu kultu ładunku - nie ma absolutnie żadnego powodu, dla którego nie można mieć $.whenfunkcji, która działała z wywołaniami zwrotnymi.
Esailija,

To jednak nie odpowiada na pytanie +1, że mógłbym wiedzieć, czym jest piekło zwrotne.
Bhojendra Rauniyar

146

Odpowiedzi te, w tym wybranego odpowiedzi są dobre dla wprowadzenia obietnic koncepcyjnie, ale brakuje w specyfice co dokładnie są różnice w terminologii, która powstaje przy użyciu bibliotek ich realizacji (i nie istotne różnice).

Ponieważ wciąż jest to rozwijająca się specyfikacja , odpowiedź pochodzi obecnie z próby zbadania zarówno referencji (jak wikipedia ), jak i implementacji (jak jQuery ):

  • Odroczony : nigdy nie opisany w popularnych odniesieniach, 1 2 3 4, ale powszechnie stosowany przez implementacje jako arbiter rozwiązywania obietnic (wdrażanie i ). 5 6 7 resolvereject

    Czasami deferreds są również obietnice (wykonawcze then), 5 6 inne czasy to postrzegane jako bardziej czysta, że odroczonego zdolne tylko rozdzielczości, i zmuszając użytkownika do dostępu obietnicę korzystania . 7 then

  • Obietnica : najbardziej wszechstronne słowo na temat omawianej strategii.

    Obiekt proxy przechowujący wynik funkcji docelowej, którego synchroniczność chcielibyśmy wyodrębnić, a także ujawniający thenfunkcję akceptującą inną funkcję docelową i zwracającą nową obietnicę. 2)

    Przykład z CommonJS :

    > asyncComputeTheAnswerToEverything()
        .then(addTwo)
        .then(printResult);
    44

     

    Zawsze opisywane w popularnych źródłach, choć nigdy nie określane, do kogo należy odpowiedzialność. 1 2 3 4

    Zawsze obecny w popularnych implementacjach i nigdy nie posiadający zdolności rozdzielczości. 5 6 7

  • Przyszłość : pozornie przestarzały termin znaleziony w niektórych popularnych odnośnikach 1 i co najmniej jednym popularnym wykonaniu 8, ale pozornie wycofywany z dyskusji zamiast terminu „obietnica” 3 i nie zawsze wymieniany w popularnych wprowadzeniach do tematu. 9

    Jednak co najmniej jedna biblioteka używa tego terminu w sposób ogólny, aby wyodrębnić synchroniczność i obsługę błędów, nie zapewniając jednak thenfunkcjonalności. 10 Nie jest jasne, czy unikanie terminu „obietnica” było zamierzone, ale prawdopodobnie jest to dobry wybór, ponieważ obietnice budowane są wokół „rzeczy niemożliwych”. 2)

Bibliografia

  1. Wikipedia na temat obietnic i kontraktów terminowych
  2. Obietnice / A + spec
  3. Standard DOM dotyczący obietnic
  4. Standard DOM obiecuje specyfikację WIP
  5. DOJO Toolkit odroczony
  6. jQuery Deferreds
  7. Q
  8. FutureJS
  9. Funkcjonalna sekcja JavaScript na temat obietnic
  10. Futures w testach integracyjnych AngularJS

Różne potencjalnie mylące rzeczy


5
Aby dodać nieco więcej wyjaśnień na temat terminu „Przyszłość” - futures mają długą historię w wielu językach programowania, sięgającą połowy lat 80-tych. Termin ten jest nadal w powszechnym użyciu, zwłaszcza w przypadku JVM. JavaScript wydaje się używać terminu „Obietnica”, aby oznaczać coś podobnego do tego, co Java oznacza „Przyszłość”. Scala dzieli tę samą koncepcję na „Przyszłość” i „Obietnica” w odniesieniu do uchwytu „czytaj” i uchwytu „zapisu” tego, co programiści JavaScript nazywają obietnicą.
Heather Miller,

1
I oczywiście Microsoft musiał wymyślić własny termin, więc w języku C # są one nazywaneTask
BlueRaja - Danny Pflughoeft

72

To, co naprawdę sprawiło, że kliknęło mnie to, to prezentacja Domenica Denicoli.

W githubist podał opis, który najbardziej mi się podoba, jest bardzo zwięzły:

Chodzi o to, aby przywrócić nam funkcjonalną kompozycję i bąbelki błędów w świecie asynchronicznym.

Innymi słowy, obietnice są sposobem, który pozwala nam pisać kod asynchroniczny, który jest prawie tak łatwy do napisania, jak gdyby był synchroniczny .

Rozważ ten przykład z obietnicami:

getTweetsFor("domenic") // promise-returning async function
    .then(function (tweets) {
        var shortUrls = parseTweetsForUrls(tweets);
        var mostRecentShortUrl = shortUrls[0];
        return expandUrlUsingTwitterApi(mostRecentShortUrl); // promise-returning async function
    })
    .then(doHttpRequest) // promise-returning async function
    .then(
        function (responseBody) {
            console.log("Most recent link text:", responseBody);
        },
        function (error) {
            console.error("Error with the twitterverse:", error);
        }
    );

Działa tak, jakbyś pisał ten kod synchroniczny:

try {
    var tweets = getTweetsFor("domenic"); // blocking
    var shortUrls = parseTweetsForUrls(tweets);
    var mostRecentShortUrl = shortUrls[0];
    var responseBody = doHttpRequest(expandUrlUsingTwitterApi(mostRecentShortUrl)); // blocking x 2
    console.log("Most recent link text:", responseBody);
} catch (error) {
    console.error("Error with the twitterverse: ", error);
}

(Jeśli nadal wydaje się to skomplikowane, obejrzyj prezentację!)

Jeśli chodzi o odroczony, jest to droga do .resolve()lub .reject()obiecuje. W specyfikacji Promises / B nazywa się to .defer(). W jQuery to jest $.Deferred().

Należy pamiętać, że o ile wiem, implementacja Promise w jQuery jest zepsuta (zobacz tę treść), przynajmniej od jQuery 1.8.2.
Podobno implementuje obietnice / annables , ale nie otrzymujesz poprawnej obsługi błędów, którą powinieneś, w tym sensie, że cała funkcja „asynchronizuj / łap” nie będzie działać. Szkoda, bo „try / catch” z kodem asynchronicznym jest całkowicie fajne.

Jeśli zamierzasz skorzystać z Obietnic (powinieneś wypróbować je z własnym kodem!), Użyj Q Kris Kowal . Wersja jQuery to tylko agregator zwrotny do pisania czystszego kodu jQuery, ale nie ma sensu.

Jeśli chodzi o przyszłość, nie mam pojęcia, nie widziałem tego w żadnym interfejsie API.

Edytuj: Dyskusja youtube Domenica Denicoli na temat obietnic z komentarza @Farm poniżej.

Cytat z Michaela Jacksona (tak, Michael Jackson ) z filmu:

Chcę, żebyś zapamiętał to zdanie: obietnica jest wartością asynchroniczną .

To doskonały opis: obietnica jest jak zmienna z przyszłości - pierwszorzędne odniesienie do czegoś, co w pewnym momencie będzie istnieć (lub się wydarzy).


5
Świetne wyjaśnienie Futures (teraz zaimplementowane w DOM!) Przez członka zespołu podstawowego W3 i Chrome można znaleźć tutaj: xanthir.com/b4PY0
oligofren

1
@oligofren Dzięki za link, to wydaje się miłe! Nawiasem mówiąc, co za tajemniczo irytujące favicon lol.
Camilo Martin

1
Ta odpowiedź wymaga o wiele więcej pozytywnych opinii. Należy głosować wyżej niż zaakceptowana odpowiedź IMO.
Chev

1
Dyskusja Domenica Denicoli na temat obietnic: youtube.com/watch?v=hf1T_AONQJU
Farma

@Farm Great! Dodam to do odpowiedzi.
Camilo Martin,

32

Obietnica reprezentuje pełnomocnik do wartości niekoniecznie wiadomo, kiedy obietnica jest tworzony. Pozwala powiązać procedury obsługi z ostateczną wartością sukcesu lub przyczyną niepowodzenia akcji asynchronicznej. Dzięki temu metody asynchroniczne zwracają wartości, takie jak metody synchroniczne: zamiast wartości końcowej metoda asynchroniczna zwraca obietnicę posiadania wartości w pewnym momencie w przyszłości.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

deferred.promise()Metoda umożliwia funkcja asynchroniczna, aby zapobiec zakłócaniu inny kod z postępem lub status swojego wniosku wewnętrznego. Obietnica ujawnia tylko odroczone metody potrzebne do dołączenia dodatkowych procedur obsługi lub określenia stanu ( wtedy zakończone, niepowodzenie, zawsze, potok, postęp, stan i obietnica ), ale nie te, które zmieniają stan ( rozwiązują, odrzucają, powiadamiają, rozwiązują, odrzucić i powiadomić ).

Jeśli podano obiekt docelowy, deferred.promise()dołączymy do niego metody, a następnie zwrócą ten obiekt, zamiast tworzyć nowy. Może to być przydatne do dołączenia zachowania Promise do obiektu, który już istnieje.

Jeśli tworzysz Odroczony, zachowaj odniesienie do Odroczonego, aby w pewnym momencie można go było rozwiązać lub odrzucić. Zwracaj tylko obiekt Promise przez deferred.promise (), aby inny kod mógł rejestrować wywołania zwrotne lub sprawdzać bieżący stan.

Po prostu możemy powiedzieć, że Obietnica reprezentuje wartość, która nie jest jeszcze znana, a jako Odroczona oznacza pracę, która nie została jeszcze ukończona.


wprowadź opis zdjęcia tutaj


1
plus 1 za reprezentację wykresu. Bravisimo !! ^ _ ^
Ashok MA

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.