Promise

Gli oggetti Promise sono usati per computazioni in differita e asincrone. Una Promise rappresenta un'operazione che non è ancora completata, ma lo sarà in futuro.

Sintassi

new Promise(function(resolve, reject) { ... });

Parametri

executor

Una funzione che ha due argomenti: resolve e reject.  Tale funzione viene chiamata immediatamente dall'implementazione della Promise, passando i due argomenti resolve e reject, che sono due funzioni. Le due funzioni resolve e reject, quando chiamate, risolvono o rigettano la promise. L'esecutore inizia del lavoro (solitamente asincrono), e, una volta completato, chiama resolve per risolvere la promise, o reject se c'è stato qualche errore. Se un errore viene sollevato nella funzione di esecuzione (executor) la promise viene rigettata.

Descrizione

Una Promise rappresenta un proxy per un valore non necessariamente noto quando la promise è stata creata.  Consente di associare degli handlers con il successo o il fallimento di un'azione asincrona  (e il "valore" in caso di successo, o la motivazione in caso di fallimento). Questo in pratica consente di utilizzare dei metodi asincroni di fatto come se fossero sincroni: la funzione che compie del lavoro asincrono non ritorna il valore di completamento ma ritorna una promise, tramite la quale si potrà ottenere il valore di completamento una volta che la promise sarà terminata.

Una Promise può presentarsi in uno dei seguenti stati:

  • pending (attesa): stato iniziale, né soddisfatto né respinto.
  • fulfilled (soddisfatto): significa che l'operazione si è conclusa con sucesso.
  • rejected (respinto): significa che l'operazione à fallita.

Una promise in pending può evolvere sia in fulfilled con un valore, sia in rejected con una motivazione (errore). Quando accade una di queste situazioni, vengono chiamati gli handler associati che sono stati accodati dal metodo then della promise. (Se la promise è già stata soddisfatta o respinta quando viene agganciato l'handler, quest'ultimo verrà chiamato immediatamente, quindi non è necessario che gli handler vengano agganciati prima del completamento dell'operazione asincrona).

Poichè i metodi Promise.prototype.then e Promise.prototype.catch restituiscono delle promise, è possibile concatenarli tramite l'operazione di composition.

Da non confondere con: molti altri linguaggi hanno meccanismi simili per la lazy evaluation ed il calcolo differito, che a loro volta vengono chiamati "promise" (es. Schemes). Le Promise in Javascript rappresentano un processo che è gia accaduto, che può essere concatenato con delle funzioni di callback. Se stai cercando di eseguire una lazy evaluation (valutazione non immediata) di un'espressione, considera l'utilizzo delle arrow function senza argomenti: f = () => expression per creare un'espressione non valutata immediatamente (lazy-evaluated) ed usare f() per valutarla.

Nota: Si dice che una promise è "ferma" (settled) se è soddisfatta o respinta, ma non in pending. Si può parlare anche di promessa "risolta" (resolved) quando la promise è ferma o è bloccata in una catena di promise. States and fates di Domenic Denicola contiene maggiori dettagli sulla terminologia riguardo le promise.

Proprietà

Promise.length
La proprietà length (lunghezza) ha come valore 1 (numero di argomenti del costruttore).
Promise.prototype
Rappresenta il prototype per il costruttore della Promise.

Metodi

Promise.all(iterable)
Ritorna una promise che si risolve quando tutte le promises dell'argomento iterabile sono state risolte. Oppure, viene rigettato appena una promise dell'argomento di tipo Iterable viene rigettato. Se tutto va a buon fine, la promise viene completata con un array contenente i valori di completamento di ciascuna promise dell'iterable, nello stesso ordine di quello dell'iterable. In caso fallisca (cioè appena una prima promise dell'iterable fallisce), Promise.all viene rigettato con la ragione (errore) della prima promise che ha fallito. Questo è utile per aggregare insieme il risultato di più promises.
Promise.race(iterable)
Restituisce una promise che si risolve o respinge, non appena una delle promises dell'iterable si risolve o respinge, con il valore o la motivazione da quella promise.
Promise.reject(reason)
Restituisce un oggetto Promise che è respinta con la data motivazione.
Promise.resolve(value)
Restituise un oggetto Promise che è risolto con il valore dato. Se il valore é un thenable (es. ha un metodo then), la promise restituita "seguirà" quel thenable, usando il suo stato; altirmenti la promise restituita sarà soddisfatta con il valore. Generalmente, se non sei sicuro che un valore sia di tipo Promise usa Promise.resolve(value) e lavora con il valore restituito dalla promise.

Promise prototype

Proprietà

Metodi

Creazione di una Promise

Un oggetto di tipo Promise, viene creato con la keyowrd new ed il suo costruttore. Questo costruttore accetta come argomento una funzione, chiamata "funzione esecutore (executor function)". Questa funzione accetta altre due funzioni come parametri. La prima (resolve) viene eseguita in modo asincrono quando l'operazione viene eseguita con successo e restituisce il risultato dell'operazione come valore. La seconda (reject) viene eseguita nel caso in cui l'operazione fallisca e restituisce il motivo per cui l'operazione non è stata eseguita: generalmente un oggetto di tipo Error

const myFirstPromise = new Promise((resolve, reject) => {
  // esegue qualcosa di asincrono che eventualmente chiama:
  //
     resolve(someValue); // fulfilled
  // oppure
     reject("motivo del fallimento"); // rejected
});

Per creare una funzione con il comportamento di Promise, semplicemente restituisci una promise

function myAsyncFunction(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
}

Esempi

Esempio semplice

let myFirstPromise = new Promise((resolve, reject) => {
  // Chiamiamo resolve(...) quando viene eseguito correttamente, e reject(...) quando fallisce.
  // In questo esempio viene utilizzato setTimeout(...) per simulare un'operazione asincrona.
  // Nella realtà probabilmente utilizzerai qualcosa del tipo XHR o HTML5 API.
  setTimeout(function(){
    resolve("Success!"); // È andato tutto perfettamente!
  }, 250);
});

myFirstPromise.then((successMessage) => {
  // successMessage viene passato alla funzione resolve(...) .
  // Non deve essere necessariamente una stringa, ma nel caso sia solo un messaggio probabilmemte lo sarà.
  console.log("Yay! " + successMessage);
});

Esempio avanzato

<button id="btn">Make a promise!</button>
<div id="log"></div>

Questo piccolo esempio mostra il meccanismo delle Promise. Il metodo testPromise() viene richiamato ogni volta che il <button> viene cliccato. Crea una promise che viene risolta correttamente (fulfilled), utilizzando window.setTimeout() che incrementa il contatore ogni 1-3 secondi (random). Il costruttore Promise viene utilizzato per creare la promise.

La risoluzione della promise viene semplicemente loggata tramite una funzione di callback fulfill p1.then(). Una serie di log mostrano che il comportamento sincrono del metodo è disaccoppiato rispetto all'esecuzione asincrona della promise.

'use strict';
var promiseCount = 0;

function testPromise() {
    let thisPromiseCount = ++promiseCount;

    let log = document.getElementById('log');
    log.insertAdjacentHTML('beforeend', thisPromiseCount +
        ') Started (<small>Sync code started</small>)<br/>');

    // We make a new promise: we promise a numeric count of this promise, starting from 1 (after waiting 3s)
    let p1 = new Promise(
        // The resolver function is called with the ability to resolve or
        // reject the promise
       (resolve, reject) => {
            log.insertAdjacentHTML('beforeend', thisPromiseCount +
                ') Promise started (<small>Async code started</small>)<br/>');
            // This is only an example to create asynchronism
            window.setTimeout(
                function() {
                    // We fulfill the promise !
                    resolve(thisPromiseCount);
                }, Math.random() * 2000 + 1000);
        }
    );

    // We define what to do when the promise is resolved with the then() call,
    // and what to do when the promise is rejected with the catch() call
    p1.then(
        // Log the fulfillment value
        function(val) {
            log.insertAdjacentHTML('beforeend', val +
                ') Promise fulfilled (<small>Async code terminated</small>)<br/>');
        }).catch(
        // Log the rejection reason
       (reason) => {
            console.log('Handle rejected promise ('+reason+') here.');
        });

    log.insertAdjacentHTML('beforeend', thisPromiseCount +
        ') Promise made (<small>Sync code terminated</small>)<br/>');
}



if ("Promise" in window) {
  let btn = document.getElementById("btn");
  btn.addEventListener("click",testPromise);
} else {
  log = document.getElementById('log');
  log.innerHTML = "Live example not available as your browser doesn't support the <code>Promise<code> interface.";
}

In questo esempio si comincia cliccando il bottone. Per testare necessiti di un browser che supporta le Promise. Cliccando il bottone diverse volte in un lasso di tempo breve vedrai che le funzioni verranno risolte una dopo l'altra.

Caricare un'immagine con XHR

Un'altro semplice esempio che utilizza le Promise e XMLHttpRequest mostra come caricare un'immagine è disponibile sul repository di MDN su Github. Puoi inoltre vederla in azione. Ogni azione è commentata e puoi seguire passo-passo come viene creata la Promise e gestita tramite XHR.

Specifiche

Supporto dei browser

BCD tables only load in the browser

Vedi anche