Quali sono le differenze tra Deferred, Promise e Future in JavaScript?


300

Quali sono le differenze tra differiti, promesse e future?
Esiste una teoria generalmente approvata dietro tutti e tre questi?


11
Non credo che questo abbia nulla a che fare con jQuery ...
BoltClock

11
Vale la pena di leggere questo: msdn.microsoft.com/en-us/scriptjunkie/gg723713
jfriend00

8
Non li ho usati io stesso, ma ecco un'introduzione abbastanza buona su wikipedia en.wikipedia.org/wiki/Futures_and_promises . Anche se non capisco perfettamente il caso d'uso correttamente. In un linguaggio asincrono guidato da eventi come javascript. A prima vista non riesco a vedere cosa offrono oltre i callback, a parte forse un'API più pulita. Mi piacerebbe se qualcuno potesse fornire un esempio d'uso e mostrare come questi concetti sono applicati e perché i callback sarebbero una soluzione inefficiente. @duri questo non ha nulla a che fare con jQuery. È possibile rimuovere il tag jQuery per favore
AshHeskes

2
@ jfriend00 ottimo collegamento, probabilmente dovrebbe essere elaborato in una risposta.
fncomp,

@ jfriend00 nuovo collegamento - msdn.microsoft.com/en-us/magazine/gg723713.aspx
C69

Risposte:


97

Alla luce dell'apparente antipatia per come ho tentato di rispondere alla domanda del PO. La risposta letterale è che una promessa è qualcosa di condiviso con altri oggetti, mentre un differito dovrebbe essere tenuto privato. In primo luogo, un differito (che generalmente estende Promessa) può risolversi da solo, mentre una promessa potrebbe non essere in grado di farlo.

Se sei interessato alle minuzie, esamina Promises / A + .


Per quanto ne so, lo scopo generale è migliorare la chiarezza e allentare l'accoppiamento attraverso un'interfaccia standardizzata. Vedi la lettura suggerita da @ jfriend00:

Invece di trasferire direttamente i callback alle funzioni, cosa che può portare a interfacce strettamente collegate, l'uso delle promesse consente di separare le preoccupazioni per il codice sincrono o asincrono.

Personalmente, ho trovato rinviato particolarmente utile quando si tratta, ad esempio, di modelli popolati da richieste asincrone, caricamento di script con reti di dipendenze e fornitura di feedback degli utenti per formare i dati in modo non bloccante.

Infatti, confronta la pura forma di callback di fare qualcosa dopo aver caricato CodeMirror in modalità JS in modo asincrono (mi scuso, non ho usato jQuery da un po ' ):

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

Alla versione formulata delle promesse (di nuovo, mi scuso, non sono aggiornato su 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.");
   });
});

Mi scuso per il semi-pseudo codice, ma spero che renda in qualche modo chiara l'idea di base. Fondamentalmente, restituendo una promessa standardizzata, è possibile passare la promessa in giro, consentendo così un raggruppamento più chiaro.


10
Sebbene questa risposta possa essere utile, in realtà non affronta la domanda: i cosiddetti differiti sono futures o promesse, a seconda dell'implementazione.
awdz9nld,

@ MartinKällman Hai ragione! Non lo rivisitavo da un po 'e ho imparato un po'. Pubblicherò una risposta separata di seguito, ma la lascerò poiché le persone sembrano aver beneficiato dell'esempio di utilizzo.
fncomp

@ MartinKällman, ho pensato di scrivere una nuova risposta. Tuttavia, penso che l'OP volesse effettivamente sapere a cosa servono le promesse e i differiti. La risposta alla sua vera domanda sarebbe, approssimativamente, "i rinviati possono risolversi da soli. AFAIK, la teoria dietro promesse e rinvii deriva da [Programmazione reattiva funzionale | haskell.org/haskellwiki/Functional_Reactive_Programming] , che è una tecnica per appiattire i callback ".
fncomp

2
Questo è totalmente sbagliato e i tuoi esempi sono altrettanto facili da fare con i callback. Le promesse non riguardano l'aggregazione del callback e il disaccoppiamento, ma fornire un DSL per scrivere codice asincrono come il codice di sincronizzazione è scritto. Soprattutto fn(callback, errback)non è più strettamente accoppiato o meno utile di fn().then(callback, errback)- ma è comunque un modo sbagliato di usare le promesse. In particolare odio l' $.whenesempio del culto del carico : non c'è assolutamente alcun motivo per cui non si possa avere una $.whenfunzione che funzioni con i callback.
Esailija,

Questo non risponde alla domanda sebbene +1 potrei essere in grado di sapere qual è l'inferno di callback.
Bhojendra Rauniyar,

146

Queste risposte, compresa la risposta selezionata, sono utili per introdurre concettualmente le promesse, ma mancano di dettagli su quali siano esattamente le differenze nella terminologia che si presenta quando si utilizzano le librerie che le implementano (e ci sono differenze importanti).

Dal momento che è ancora una specifica in evoluzione , la risposta attualmente proviene dal tentativo di esaminare sia i riferimenti (come Wikipedia ) sia le implementazioni (come jQuery ):

  • Differito : mai descritto nei riferimenti popolari, 1 2 3 4 ma comunemente usato dalle implementazioni come arbitro della risoluzione della promessa (implementazione e ). 5 6 7 resolvereject

    A volte sono anche deferreds promesse (di attuazione then), 5 6 altre volte è visto come più puro di avere l'anticipate solo in grado di risoluzione, e costringendo l'utente ad accedere la promessa per l'utilizzo . 7 then

  • Promessa : la parola più onnicomprensiva per la strategia in discussione.

    Un oggetto proxy che memorizza il risultato di una funzione target di cui vorremmo astrarre la sincronicità, oltre a esporre una thenfunzione che accetta un'altra funzione target e restituisce una nuova promessa. 2

    Esempio da CommonJS :

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

     

    Descritto sempre nei riferimenti popolari, anche se non è mai stato specificato in merito alla cui responsabilità rientra la risoluzione. 1 2 3 4

    Presente sempre nelle implementazioni popolari e mai dato le capacità di risoluzione. 5 6 7

  • Futuro : un termine apparentemente deprecato trovato in alcuni riferimenti popolari 1 e in almeno un'implementazione popolare 8 , ma apparentemente eliminato gradualmente dalla discussione in preferenza del termine "promessa" 3 e non sempre menzionato nelle introduzioni popolari all'argomento. 9

    Tuttavia, almeno una libreria utilizza il termine genericamente per astrarre la sincronicità e la gestione degli errori, senza fornire thenfunzionalità. 10 Non è chiaro se evitare il termine "promessa" fosse intenzionale, ma probabilmente una buona scelta poiché le promesse sono costruite intorno a "fattibili". 2

Riferimenti

  1. Wikipedia su promesse e futuri
  2. Promesse / A + spec
  3. Standard DOM sulle promesse
  4. DOM standard promesse WIP specifiche
  5. DOJO Toolkit Deferreds
  6. jQuery Deferreds
  7. Q
  8. FutureJS
  9. Sezione Javascript funzionale su Promesse
  10. Futuri nei test di integrazione di AngularJS

Varie cose potenzialmente confuse


5
Per aggiungere un po 'più di chiarimenti sul termine "futuro", i futures hanno una lunga storia in molti linguaggi di programmazione risalenti alla metà degli anni '80. E il termine è ancora ampiamente utilizzato oggi, in particolare sulla JVM. JavaScript sembra aver scelto di usare il termine "Promessa" per indicare qualcosa di simile a ciò che Java significa "Futuro". Scala separa lo stesso concetto in "Futuro" e "Promessa" per fare riferimento all'handle "read" e all'handle "write" di ciò che i programmatori JavaScript chiamano Promise.
Heather Miller,

1
E ovviamente Microsoft ha dovuto escogitare il proprio termine, quindi in C # si chiamanoTask
BlueRaja - Danny Pflughoeft,

72

Ciò che ha fatto davvero scattare tutto per me è stata questa presentazione di Domenic Denicola.

In poche parole , ha dato la descrizione che mi piace di più, è molto concisa:

Il punto delle promesse è di restituirci composizione funzionale ed errori che ribollono nel mondo asincrono.

In altre parole, le promesse sono un modo che ci consente di scrivere codice asincrono che è quasi facile da scrivere come se fosse sincrono .

Considera questo esempio, con le promesse:

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

Funziona come se stessi scrivendo questo codice sincrono:

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

(Se sembra ancora complicato, guarda quella presentazione!)

Per quanto riguarda il differito, è un modo .resolve()o .reject()promesse. Nella specifica Promises / B , viene chiamato .defer(). In jQuery, lo è $.Deferred().

Si noti che, per quanto ne so, l'implementazione di Promise in jQuery è interrotta (si veda quel dato), almeno a partire da jQuery 1.8.2.
Presumibilmente implementa promesse / A quindi , ma non ottieni la corretta gestione degli errori che dovresti, nel senso che l'intera funzionalità "async try / catch" non funzionerà. È un peccato, perché avere un "try / catch" con codice asincrono è assolutamente fantastico.

Se hai intenzione di usare le promesse (dovresti provarle con il tuo codice!), Usa la Q di Kris Kowal . La versione jQuery è solo un aggregatore di callback per scrivere codice jQuery più pulito, ma manca il punto.

Per quanto riguarda il futuro, non ne ho idea, non l'ho visto in nessuna API.

Modifica: il discorso su YouTube di Domenic Denicola su Promesse dal commento di @Farm qui sotto.

Una citazione da Michael Jackson (sì, Michael Jackson ) dal video:

Voglio che tu bruci questa frase nella tua mente: una promessa è un valore asincrono .

Questa è una descrizione eccellente: una promessa è come una variabile dal futuro - un riferimento di prima classe a qualcosa che, ad un certo punto, esisterà (o accadrà).


5
Una grande spiegazione di Futures (ora implementata nel DOM!) Da un membro del core team di W3 e Chrome può essere trovata qui: xanthir.com/b4PY0
oligofren

1
@oligofren Grazie per il link, mi sembra carino! A proposito, che favicon misteriosamente fastidioso lol.
Camilo Martin,

1
Questa risposta richiede molti più voti. Dovrebbe essere votato più in alto rispetto alla risposta accettata IMO.
Chev,

1
Il talk di YouTube di Domenic Denicola sulle promesse: youtube.com/watch?v=hf1T_AONQJU
Farm

@Farm Great! Lo aggiungerò alla risposta.
Camilo Martin,

32

Una promessa rappresenta un proxy per un valore non necessariamente noto al momento della creazione della promessa. Consente di associare i gestori a un valore di successo o motivo di errore di un'azione asincrona. Ciò consente ai metodi asincroni di restituire valori come i metodi sincroni: invece del valore finale, il metodo asincrono restituisce la promessa di avere un valore in futuro.

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

Il deferred.promise()metodo consente a una funzione asincrona di impedire ad altri codici di interferire con l'avanzamento o lo stato della sua richiesta interna. La Promessa espone solo i metodi differiti necessari per collegare gestori aggiuntivi o determinare lo stato ( quindi, fatto, fallito, sempre, pipe, progresso, stato e promessa ), ma non quelli che cambiano lo stato ( risoluzione, rifiuto, notifica, risoluzione Con, rejectWith e notifyWith ).

Se viene fornito un target, deferred.promise()si collegheranno i metodi su di esso e quindi verrà restituito questo oggetto anziché crearne uno nuovo. Ciò può essere utile per associare il comportamento Promessa a un oggetto già esistente.

Se stai creando un differito, conserva un riferimento al differito in modo che possa essere risolto o rifiutato a un certo punto. Restituisce solo l'oggetto Promise tramite deferred.promise () in modo che altri codici possano registrare callback o ispezionare lo stato corrente.

Semplicemente possiamo dire che una Promessa rappresenta un valore che non è ancora noto laddove un Differito rappresenta un'opera che non è ancora finita.


inserisci qui la descrizione dell'immagine


1
più 1 per la rappresentazione del grafico. Bravisimo !! ^ _ ^
Ashok MA,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.