Ricerca…


Sintassi

  • nuova promessa (/ * funzione esecutore: * / funzione (risoluzione, rifiuto) {})
  • promise.then (onFulfilled [, onRejected])
  • promise.catch (onRejected)
  • Promise.resolve (risoluzione)
  • Promise.reject (ragione)
  • Promise.all (iterable)
  • Promise.race (iterable)

Osservazioni

Le promesse fanno parte delle specifiche di ECMAScript 2015 e il supporto del browser è limitato, con l'88% dei browser in tutto il mondo che lo supportano a partire da luglio 2017. La tabella seguente offre una panoramica delle prime versioni del browser che forniscono supporto per le promesse.

Cromo Bordo Firefox Internet Explorer musica lirica Opera Mini Safari Safari iOS
32 12 27 X 19 X 7.1 8

In ambienti che non li supportano, Promise può essere polyfilled. Le librerie di terze parti possono anche fornire funzionalità estese, come la "promisurazione" automatica delle funzioni di callback o metodi aggiuntivi come il progress noto anche come notify .

Il sito web standard Promises / A + fornisce un elenco di implementazioni conformi a 1.0 e 1.1 . Prometti callback basati sullo standard A + vengono sempre eseguiti in modo asincrono come microtasks nel ciclo degli eventi .

Prometti concatenamento

Il metodo then di una promessa restituisce una nuova promessa.

const promise = new Promise(resolve => setTimeout(resolve, 5000));

promise
    // 5 seconds later
    .then(() => 2)
    // returning a value from a then callback will cause
    // the new promise to resolve with this value
    .then(value => { /* value === 2 */ });

Restituendo una Promise da un callback then lo aggiungerà alla catena di promesse.

function wait(millis) {
    return new Promise(resolve => setTimeout(resolve, millis));
}

const p = wait(5000).then(() => wait(4000)).then(() => wait(1000));
p.then(() => { /* 10 seconds have passed */ });

Una catch consente a una promessa rifiutata di recuperare, in modo simile a come funziona il catch in una dichiarazione try / catch . Qualsiasi incatenato then dopo una catch eseguirà il suo gestore di determinazione utilizzando il valore risolto dalla catch .

const p = new Promise(resolve => {throw 'oh no'});
p.catch(() => 'oh yes').then(console.log.bind(console));  // outputs "oh yes"

Se non ci sono operatori di catch o reject nel mezzo della catena, un catch alla fine catturerà qualsiasi rifiuto nella catena:

p.catch(() => Promise.reject('oh yes'))
  .then(console.log.bind(console))      // won't be called
  .catch(console.error.bind(console));  // outputs "oh yes"

In alcune occasioni, potresti voler "ramificare" l'esecuzione delle funzioni. Puoi farlo restituendo diverse promesse da una funzione a seconda della condizione. Più avanti nel codice, è possibile unire tutti questi rami in uno per chiamare altre funzioni su di essi e / o per gestire tutti gli errori in un unico punto.

promise
    .then(result => {          
        if (result.condition) {
            return handlerFn1() 
                .then(handlerFn2);
        } else if (result.condition2) {
            return handlerFn3()
                .then(handlerFn4);
        } else {
            throw new Error("Invalid result");
        }
    })
    .then(handlerFn5)
    .catch(err => {
        console.error(err);
    });

Pertanto, l'ordine di esecuzione delle funzioni è simile a:

promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
         |                            ^
         V                            |
         -> handlerFn3 -> handlerFn4 -^            

La singola catch otterrà l'errore su qualsiasi ramo si verifichi.

introduzione

Un oggetto Promise rappresenta un'operazione che ha prodotto o che alla fine produrrà un valore. Le promesse forniscono un modo efficace per avvolgere il risultato (possibilmente in sospeso) del lavoro asincrono, attenuando il problema dei callback profondamente nidificati (noto come " inferno di callback ").

Stati e controllo del flusso

Una promessa può essere in uno dei tre stati:

  • in sospeso - L'operazione sottostante non è stata ancora completata e la promessa è in attesa di adempimento.
  • soddisfatto - L'operazione è finita e la promessa è soddisfatta con un valore . Questo è analogo alla restituzione di un valore da una funzione sincrona.
  • respinto - Si è verificato un errore durante l'operazione e la promessa viene respinta per un motivo . Questo è analogo al lancio di un errore in una funzione sincrona.

Si dice che una promessa sia risolta (o risolta ) quando è soddisfatta o respinta. Una volta stabilita una promessa, diventa immutabile e il suo stato non può cambiare. I metodi then e catch di una promessa possono essere utilizzati per allegare i callback che vengono eseguiti quando viene risolto. Questi callback vengono richiamati rispettivamente con il valore di evasione e il motivo di rifiuto.

Prometti il ​​diagramma di flusso

Esempio

const promise = new Promise((resolve, reject) => {
    // Perform some work (possibly asynchronous)
    // ...

    if (/* Work has successfully finished and produced "value" */) {
        resolve(value);
    } else {
        // Something went wrong because of "reason"
        // The reason is traditionally an Error object, although
        // this is not required or enforced.
        let reason = new Error(message);
        reject(reason);

        // Throwing an error also rejects the promise.
        throw reason;
    }
});

I metodi then e catch possono essere utilizzati per allegare callback di adempimento e rifiuto:

promise.then(value => {
    // Work has completed successfully,
    // promise has been fulfilled with "value"
}).catch(reason => {
    // Something went wrong,
    // promise has been rejected with "reason"
});

Nota: la chiamata di promise.then(...) e promise.catch(...) sulla stessa promessa potrebbe comportare Uncaught exception in Promise se si verifica un errore, durante l'esecuzione della promessa o all'interno di uno dei callback, quindi il modo preferito sarebbe quello di collegare il prossimo ascoltatore alla promessa restituita dal precedente then / catch .

In alternativa, entrambe le callback possono essere allegate in una singola chiamata per then :

promise.then(onFulfilled, onRejected);

Allegando i callback a una promessa che è già stata risolta, li inseriremo immediatamente nella coda del microtask e verranno richiamati "il prima possibile" (cioè immediatamente dopo lo script attualmente in esecuzione). Non è necessario verificare lo stato della promessa prima di allegare i callback, diversamente da molte altre implementazioni che generano eventi.


Dimostrazione dal vivo

Chiamata funzione di ritardo

Il metodo setTimeout() chiama una funzione o valuta un'espressione dopo un numero specificato di millisecondi. È anche un modo banale per ottenere un'operazione asincrona.

In questo esempio, la chiamata alla funzione wait risolve la promessa dopo il tempo specificato come primo argomento:

function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));  
}

wait(5000).then(() => { 
    console.log('5 seconds have passed...');
});

In attesa di più promesse simultanee

Il metodo statico Promise.all() accetta un iterable (ad esempio una Array ) di promesse e restituisce una nuova promessa, che si risolve quando tutte le promesse nell'iterable si sono risolte, o rifiuta se almeno una delle promesse nell' iterable è stata respinta.

// wait "millis" ms, then resolve with "value"
function resolve(value, milliseconds) {
    return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}

// wait "millis" ms, then reject with "reason"
function reject(reason, milliseconds) {
    return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    resolve(3, 7000)    
]).then(values => console.log(values)); // outputs "[1, 2, 3]" after 7 seconds.

Promise.all([
    resolve(1, 5000),
    reject('Error!', 6000),
    resolve(2, 7000)
]).then(values => console.log(values)) // does not output anything
.catch(reason => console.log(reason)); // outputs "Error!" after 6 seconds.

I valori non promettenti nel iterable sono "promisi" .

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    { hello: 3 }
])
.then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds

L'incarico di distruzione può aiutare a recuperare i risultati da molteplici promesse.

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    resolve(3, 7000)
])
.then(([result1, result2, result3]) => {
    console.log(result1);
    console.log(result2);
    console.log(result3);
});

Aspettando la prima delle molteplici promesse simultanee

Il metodo statico Promise.race() accetta un iterable di Promises e restituisce una nuova Promessa che risolve o rifiuta non appena la prima delle promesse nell'iterable è stata risolta o respinta.

// wait "milliseconds" milliseconds, then resolve with "value"
function resolve(value, milliseconds) {
    return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}

// wait "milliseconds" milliseconds, then reject with "reason"
function reject(reason, milliseconds) {
    return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}

Promise.race([
    resolve(1, 5000),
    resolve(2, 3000),
    resolve(3, 1000)
])
.then(value => console.log(value)); // outputs "3" after 1 second.


Promise.race([
    reject(new Error('bad things!'), 1000),
    resolve(2, 2000)
])
.then(value => console.log(value)) // does not output anything
.catch(error => console.log(error.message)); // outputs "bad things!" after 1 second

Valori "promettenti"

Il metodo statico Promise.resolve può essere utilizzato per avvolgere i valori in promesse.

let resolved = Promise.resolve(2);
resolved.then(value => {
    // immediately invoked
    // value === 2
});

Se il value è già una promessa, Promise.resolve semplicemente lo Promise.resolve .

let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
let two = Promise.resolve(one);
two.then(value => {
    // 1 second has passed
    // value === 2
});

In effetti, il value può essere qualsiasi "percorribile" (oggetto che definisce un metodo then che funziona sufficientemente come una promessa conforme alle specifiche). Ciò consente a Promise.resolve di convertire oggetti di terze parti non attendibili in promesse di parte 1 attendibili.

let resolved = Promise.resolve({
    then(onResolved) {
        onResolved(2);
    }
});
resolved.then(value => {
    // immediately invoked
    // value === 2
});

Il metodo statico Promise.reject restituisce una promessa che immediatamente rifiuta con il reason .

let rejected = Promise.reject("Oops!");
rejected.catch(reason => {
    // immediately invoked
    // reason === "Oops!"
});

Funzioni "Promisifying" con callback

Data una funzione che accetta un callback in stile nodo,

fooFn(options, function callback(err, result) { ... });

puoi prometterlo (convertirlo in una funzione basata su promesse) come questo:

function promiseFooFn(options) {
    return new Promise((resolve, reject) =>
        fooFn(options, (err, result) =>
            // If there's an error, reject; otherwise resolve
            err ? reject(err) : resolve(result)
        )
    );
}

Questa funzione può quindi essere utilizzata come segue:

promiseFooFn(options).then(result => {
    // success!
}).catch(err => {
    // error!
});

In un modo più generico, ecco come promettere una determinata funzione di callback-style:

function promisify(func) {
    return function(...args) {
        return new Promise((resolve, reject) => {
            func(...args, (err, result) => err ? reject(err) : resolve(result));
        });
    }
}

Questo può essere usato in questo modo:

const fs = require('fs');
const promisedStat = promisify(fs.stat.bind(fs));

promisedStat('/foo/bar')
    .then(stat => console.log('STATE', stat))
    .catch(err => console.log('ERROR', err));

Gestione degli errori

Gli errori generati dalle promesse vengono gestiti dal secondo parametro ( reject ) passato a then o dal gestore passato a catch :

throwErrorAsync()
  .then(null, error => { /* handle error here */ });
// or
throwErrorAsync()
  .catch(error => { /* handle error here */ });

chaining

Se si dispone di una catena di promesse, allora un errore causerà la mancata resolve gestori:

throwErrorAsync()
  .then(() => { /* never called */ })
  .catch(error => { /* handle error here */ });

Lo stesso vale per le tue funzioni then . Se un gestore di resolve genera un'eccezione, verrà richiamato il prossimo gestore di reject :

doSomethingAsync()
  .then(result => { throwErrorSync(); })
  .then(() => { /* never called */ })
  .catch(error => { /* handle error from throwErrorSync() */ });

Un gestore di errori restituisce una nuova promessa, consentendo di continuare una catena di promesse. La promessa restituita dal gestore degli errori viene risolta con il valore restituito dal gestore:

throwErrorAsync()
  .catch(error => { /* handle error here */; return result; })
  .then(result => { /* handle result here */ });

Puoi lasciare che un errore si sovrapponga a una catena di promesse rilanciando l'errore:

throwErrorAsync()
  .catch(error => {
      /* handle error from throwErrorAsync() */
      throw error;
  })
  .then(() => { /* will not be called if there's an error */ })
  .catch(error => { /* will get called with the same error */ });

È possibile generare un'eccezione che non è gestita dalla promessa avvolgendo l'istruzione throw all'interno di un callback setTimeout :

new Promise((resolve, reject) => {
  setTimeout(() => { throw new Error(); });
});

Funziona perché le promesse non possono gestire eccezioni generate in modo asincrono.

Rifiuti non gestiti

Un errore verrà ignorato silenziosamente se una promessa non ha un blocco catch o un gestore di reject :

throwErrorAsync()
  .then(() => { /* will not be called */ });
// error silently ignored

Per evitare ciò, usa sempre un blocco catch :

throwErrorAsync()
  .then(() => { /* will not be called */ })
  .catch(error => { /* handle error*/ });
// or
throwErrorAsync()
  .then(() => { /* will not be called */ }, error => { /* handle error*/ });

In alternativa, iscriviti all'evento unhandledrejection per raccogliere eventuali promesse respinte non gestite:

window.addEventListener('unhandledrejection', event => {});

Alcune promesse possono gestire il loro rifiuto più tardi del loro tempo di creazione. L'evento di rejectionhandled viene licenziato ogni volta che viene gestita una tale promessa:

window.addEventListener('unhandledrejection', event => console.log('unhandled'));
window.addEventListener('rejectionhandled', event => console.log('handled'));
var p = Promise.reject('test');

setTimeout(() => p.catch(console.log), 1000);

// Will print 'unhandled', and after one second 'test' and 'handled'

L'argomento event contiene informazioni sul rifiuto. event.reason è l'oggetto error e event.promise è l'oggetto promessa che ha causato l'evento.

In Nodejs le rejectionhandled e unhandledrejection eventi sono chiamati rejectionHandled e unhandledRejection sul process , rispettivamente, e hanno una firma diversa:

process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});

L'argomento reason è l'oggetto error e l'argomento promise è un riferimento all'oggetto promessa che ha causato l'attivazione dell'evento.

L'utilizzo di questi eventi unhandledrejection e rejectionhandled essere considerato solo a scopo di debug. In genere, tutte le promesse dovrebbero gestire i loro rifiuti.

Nota: al momento, solo Chrome 49+ e Node.js supportano eventi unhandledrejection gestiti e rejectionhandled .

Avvertenze

Concatenare con fulfill e reject

La funzione then(fulfill, reject) (con entrambi i parametri non null ) ha un comportamento unico e complesso e non dovrebbe essere utilizzata a meno che non si sappia esattamente come funziona.

La funzione funziona come previsto se data null per uno degli input:

// the following calls are equivalent
promise.then(fulfill, null) 
promise.then(fulfill)

// the following calls are also equivalent
promise.then(null, reject) 
promise.catch(reject)

Tuttavia, adotta un comportamento univoco quando vengono forniti entrambi gli input:

// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.then(fulfill).catch(reject)

// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.catch(reject).then(fulfill)

La funzione then(fulfill).catch(reject) then(fulfill, reject) sembra essere una scorciatoia per then(fulfill).catch(reject) , ma non lo è, e causerà problemi se usata in modo intercambiabile. Uno di questi problemi è che il gestore di reject non gestisce gli errori dal gestore di fulfill . Ecco cosa succederà:

Promise.resolve() // previous promise is fulfilled
    .then(() => { throw new Error(); }, // error in the fulfill handler
        error => { /* this is not called! */ });

Il codice sopra comporterà una promessa respinta perché l'errore è propagato. Confrontalo con il seguente codice, che si traduce in una promessa soddisfatta:

Promise.resolve() // previous promise is fulfilled
    .then(() => { throw new Error(); }) // error in the fulfill handler
    .catch(error => { /* handle error */ });

Un problema simile esiste quando si usa then(fulfill, reject) intercambiabile con catch(reject).then(fulfill) , eccetto con la propagazione di promesse soddisfatte invece di promesse respinte.

Lancio sincrono da una funzione che dovrebbe restituire una promessa

Immagina una funzione come questa:

function foo(arg) {
  if (arg === 'unexepectedValue') {
    throw new Error('UnexpectedValue')
  }

  return new Promise(resolve => 
    setTimeout(() => resolve(arg), 1000)
  )
}

Se tale funzione viene utilizzata nel mezzo di una catena di promesse, apparentemente non ci sono problemi:

makeSomethingAsync().
  .then(() => foo('unexpectedValue'))
  .catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here

Tuttavia, se la stessa funzione viene chiamata al di fuori di una catena di promesse, allora l'errore non verrà gestito da esso e verrà lanciato all'applicazione:

foo('unexpectedValue') // <-- error will be thrown, so the application will crash
  .then(makeSomethingAsync) // <-- will not run
  .catch(err => console.log(err)) // <-- will not catch

Esistono 2 possibili soluzioni:

Restituisci una promessa respinta con l'errore

Invece di lanciare, fai come segue:

function foo(arg) {
  if (arg === 'unexepectedValue') {
    return Promise.reject(new Error('UnexpectedValue'))
  }

  return new Promise(resolve => 
    setTimeout(() => resolve(arg), 1000)
  )
}

Avvolgi la tua funzione in una catena di promesse

La tua frase di throw verrà presa correttamente quando si trova già all'interno di una catena di promesse:

function foo(arg) {
  return Promise.resolve()
    .then(() => {
      if (arg === 'unexepectedValue') {
        throw new Error('UnexpectedValue')
      }

      return new Promise(resolve => 
        setTimeout(() => resolve(arg), 1000)
      )
    })
}

Riconciliazione delle operazioni sincrone e asincrone

In alcuni casi è possibile che si desideri racchiudere un'operazione sincrona all'interno di una promessa per impedire la ripetizione nei rami del codice. Prendi questo esempio:

if (result) { // if we already have a result
  processResult(result); // process it
} else {
  fetchResult().then(processResult);
}

I rami sincroni e asincroni del codice precedente possono essere riconciliati avvolgendo in modo ridondante l'operazione sincrona all'interno di una promessa:

var fetch = result
  ? Promise.resolve(result)
  : fetchResult();

fetch.then(processResult);

Quando si esegue il caching del risultato di una chiamata asincrona, è preferibile memorizzare nella cache la promessa anziché il risultato stesso. Ciò garantisce che è necessaria solo un'operazione asincrona per risolvere più richieste parallele.

È necessario prestare attenzione per invalidare i valori memorizzati nella cache quando si verificano condizioni di errore.

// A resource that is not expected to change frequently
var planets = 'http://swapi.co/api/planets/';
// The cached promise, or null
var cachedPromise;

function fetchResult() {
    if (!cachedPromise) {
        cachedPromise = fetch(planets)
            .catch(function (e) {
                // Invalidate the current result to retry on the next fetch
                cachedPromise = null;
                // re-raise the error to propagate it to callers
                throw e;
            });
    }
    return cachedPromise;
}

Riduci un array alle promesse concatenate

Questo modello di progettazione è utile per generare una sequenza di azioni asincrone da un elenco di elementi.

Ci sono due varianti:

  • la "quindi" riduzione, che costruisce una catena che continua finché la catena sperimenta il successo.
  • la riduzione "catch", che costruisce una catena che continua finché la catena sperimenta l'errore.

La "quindi" riduzione

Questa variante del modello crea una catena .then() e potrebbe essere utilizzata per concatenare le animazioni o per creare una sequenza di richieste HTTP dipendenti.

[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.then(() => {
        console.log(n);
        return new Promise(res => setTimeout(res, 1000));
    });
}, Promise.resolve()).then(
    () => console.log('done'),
    (e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals

Spiegazione:

  1. Chiamiamo .reduce() su un array sorgente e forniamo Promise.resolve() come valore iniziale.
  2. Ogni elemento ridotto aggiungerà un .then() al valore iniziale.
  3. reduce() prodotto s' sarà Promise.resolve (). allora (...). allora (...).
  4. Aggiungiamo manualmente un .then(successHandler, errorHandler) dopo la riduzione, per eseguire successHandler una volta successHandler tutti i passaggi precedenti. Se un passo dovesse fallire, errorHandler verrebbe eseguito.

Nota: la riduzione "allora" è una controparte sequenziale di Promise.all() .

La riduzione "cattura"

Questa variante del modello crea una catena .catch() e potrebbe essere utilizzata per sondare in sequenza una serie di server Web per alcune risorse con mirroring fino a quando non viene trovato un server funzionante.

var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.catch(() => {
        console.log(n);
        if(n === working_resource) { // 5 is working
            return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
        } else { // all other values are not working
            return new Promise((resolve, reject) => setTimeout(reject, 1000));
        }
    });
}, Promise.reject()).then(
    (n) => console.log('success at: ' + n),
    () => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals

Spiegazione:

  1. Chiamiamo .reduce() su un array sorgente e forniamo Promise.reject() come valore iniziale.
  2. Ogni elemento ridotto aggiungerà un .catch() al valore iniziale.
  3. reduce() prodotto s' sarà Promise.reject().catch(...).catch(...) .
  4. Aggiungiamo manualmente .then(successHandler, errorHandler) dopo la riduzione, per eseguire successHandler una volta successHandler tutti i passaggi precedenti. Se tutti i passaggi dovessero fallire, errorHandler verrebbe eseguito.

Nota: la riduzione "catch" è una controparte sequenziale di Promise.any() (implementata in bluebird.js , ma non attualmente in ECMAScript nativo).

per tutti gli impegni

È possibile applicare efficacemente una funzione ( cb ) che restituisce una promessa a ciascun elemento di un array, con ogni elemento che attende di essere elaborato fino a quando l'elemento precedente non viene elaborato.

function promiseForEach(arr, cb) {
  var i = 0;

  var nextPromise = function () {
    if (i >= arr.length) {
      // Processing finished.
      return;
    }

    // Process next function. Wrap in `Promise.resolve` in case
    // the function does not return a promise
    var newPromise = Promise.resolve(cb(arr[i], i));
    i++;
    // Chain to finish processing.
    return newPromise.then(nextPromise);
  };

  // Kick off the chain.
  return Promise.resolve().then(nextPromise);
};

Questo può essere utile se è necessario elaborare in modo efficiente migliaia di elementi, uno alla volta. L'utilizzo di un ciclo regolare for creare le promesse li creerà tutti in una volta e occuperà una quantità significativa di RAM.

Esecuzione della pulizia con finally ()

Attualmente v'è una proposta (non ancora parte dello standard ECMAScript) per aggiungere una finally richiamata alle promesse che verranno eseguiti indipendentemente dal fatto che la promessa si compie o rifiutata. Semanticamente, questo è simile alla clausola finally del blocco try .

Di solito utilizzi questa funzionalità per la pulizia:

var loadingData = true;

fetch('/data')
    .then(result => processData(result.data))
    .catch(error => console.error(error))
    .finally(() => {
        loadingData = false;
    });

E 'importante notare che la finally di callback non influisce sullo stato della promessa. Non importa quale valore ritorni, la promessa rimane nello stato soddisfatto / rifiutato che aveva prima. Così, nell'esempio di cui sopra la promessa sarà risolto con il valore di ritorno di processData(result.data) anche se la finally di callback restituita undefined .

Con il processo di standardizzazione essendo ancora in corso, l'implementazione promesse molto probabilmente non supporterà finally callback fuori dalla scatola. Per i callback sincroni è tuttavia possibile aggiungere questa funzionalità con un polyfill:

if (!Promise.prototype.finally) {
    Promise.prototype.finally = function(callback) {
        return this.then(result => {
            callback();
            return result;
        }, error => {
            callback();
            throw error;
        });
    };
}

Richiesta API asincrona

Questo è un esempio di una semplice chiamata API GET avvolta in una promessa di sfruttare la sua funzionalità asincrona.

var get = function(path) {
  return new Promise(function(resolve, reject) {
    let request = new XMLHttpRequest();
    request.open('GET', path);
    request.onload = resolve;
    request.onerror = reject;
    request.send();
  });
};

È possibile eseguire una gestione degli errori più robusta utilizzando le seguenti funzioni onload e onerror .

request.onload = function() {
  if (this.status >= 200 && this.status < 300) {
    if(request.response) {
      // Assuming a successful call returns JSON
      resolve(JSON.parse(request.response));
    } else {
      resolve();
  } else {
    reject({
      'status': this.status,
      'message': request.statusText
    });
  }
};

request.onerror = function() {
  reject({
    'status': this.status,
    'message': request.statusText
  });
};

Utilizzo di ES2017 async / await

Lo stesso esempio sopra, caricamento dell'immagine , può essere scritto usando le funzioni asincrone . Ciò consente anche di utilizzare il comune metodo try/catch per la gestione delle eccezioni.

Nota: a partire da aprile 2017, le versioni correnti di tutti i browser, tranne Internet Explorer, supportano le funzioni asincrone .

function loadImage(url) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.addEventListener('load', () => resolve(img));
        img.addEventListener('error', () => {
            reject(new Error(`Failed to load ${url}`));
        });
        img.src = url;
    });
}

(async () => {

    // load /image.png and append to #image-holder, otherwise throw error
    try {
        let img = await loadImage('http://example.com/image.png');
        document.getElementById('image-holder').appendChild(img);
    }
    catch (error) {
        console.error(error);
    }

})();


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow