Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 95 di 112
  • livello avanzato
Indice lezioni

Combinazioni di promise, all e race

Combinare diverse promise per rendere più efficienti le chiamate al server e sfruttare appieno la loro natura di chiamate asincrone.
Combinare diverse promise per rendere più efficienti le chiamate al server e sfruttare appieno la loro natura di chiamate asincrone.
Link copiato negli appunti

Abbiamo già visto come concatenare più promise sequenzializzando di fatto attività asincrone. Riprendiamo il codice del nostro esempio, in cui il recupero asincrono dei dati di un blog avviene solo dopo che sono stati recuperati i dati dell'utente:

getUtente()
.then(getBlog)
.then(displayBlog)
.catch(gestisciErrore);

Non sempre però questo è l'effetto desiderato o conveniente. Supponiamo, ad esempio, che oltre ai post del blog del nostro utente vogliamo mostrare anche le foto. Supponendo anche di aver definito la funzione getFoto() per il recupero asincrono delle foto dell'utente e la funzione displayFoto() per visualizzarle, il nostro codice potrebbe diventare come mostrato di seguito:

getUtente()
.then(getBlog)
.then(displayBlog)
.catch(gestisciErrore);
getUtente()
.then(getFoto)
.then(displayFoto)
.catch(gestisciErrore);

In questo caso effettueremmo due chiamate al server per caricare i dati dello stesso utente, soluzione quindi non particolarmente efficiente. In alternativa potremmo organizzare le chiamate in questo modo:

getUtente()
.then(function(utente) {
	getBlog(utente)
	.then(displayBlog);
	getFoto(utente)
	.then(getFoto);
})
.catch(gestisciErrore);

Possiamo così sfruttare il risultato del caricamento dell'utente per effettuare le due chiamate per il recupero di blog e foto. Ma anche in questo caso abbiamo un effetto indesiderato: in caso di fallimento di una delle due chiamate, la promise rigettata non verrà catturata dal metodo catch().

La funzione che si occupa di recuperare i blog e le foto dell'utente non restituisce alcuna promise. D'altronde al suo interno vengono effettuate due chiamate asincrone e quindi vengono generate due promise: quale delle due dovremmo restituire?

Ci serve un meccanismo che permetta di combinare il risultato delle due promise.

Possiamo combinare il risultato di più promise utilizzando i metodi del costruttore Promise:

  • all(), crea una promise che viene risolta quanto vengono risolte tutte le promise appartenenti ad uno specifico elenco;
  • race(), crea una promise che viene risolta quando una qualsiasi promise di un elenco viene risolta.

Proviamo a spiegare il concetto con un esempio. Consideriamo il seguente codice:

getUtente()
.then(function(utente) {
	var promiseList = [];
	var blog = getBlog(utente);
	var foto = getFoto(utente);
	promiseList.push(blog);
	promiseList.push(foto);
	return Promise.all(promiseList)
	       .then(function(risultati) {
				displayBlog(risultati[0]);
				displayFoto(risultati[1]);
		   });
})
.catch(gestisciErrore);

In questo caso abbiamo definito un array promiseList in cui abbiamo inserito le promise generate tramite le funzioni getBlog() e getFoto(). Abbiamo quindi passato questo array al metodo all() del costruttore Promise. Questo metodo restituisce una nuova promise a partire dalle due promise presenti nell'array. La promise così generata sarà risolta solo quando entrambe le promise originarie sono state risolte.

In caso di fallimento di una delle promise originarie, la nuova promise sarà rigettata e catturata dal metodo catch(). Se invece entrambe le promise vengono risolte, verrà passata alla funzione di risoluzione della promise un array con i valori risultanti nello stesso ordine con cui le promise corrispondenti sono state inserite nell'array. Nel nostro esempio avremo come primo risultato il blog dell'utente e come secondo risultato le sue foto.

Se invece vogliamo visualizzare indifferentemente i post del blog dell'utente oppure le sue foto, possiamo impostare il seguente codice:

getUtente()
.then(function(utente) {
	var promiseList = [];
	var blog = getBlog(utente);
	var foto = getFoto(utente);
	promiseList.push(blog);
	promiseList.push(foto);
	return Promise.race(promiseList)
		   .then(function(risultato) {
				if (risultato.post) {
					displayBlog(risultato);
				} else {
					displayFoto(risultato);
				}
		   });
	})
.catch(gestisciErrore);

In questo caso passiamo l'array di promise al metodo race() che restituisce una promise che sarà risolta non appena una delle promise originarie viene risolta. Quindi la richiesta HTTP che per prima riceve una risposta positiva permette di risolvere la relativa promise ignorando il risultato della seconda richiesta.

Avremo un unico valore come risultato della risoluzione della promise: o il blog oppure le foto dell'utente. Nel nostro esempio, per stabilire cosa ci è stato restituito abbiamo verificato l'esistenza della proprietà post: se presente abbiamo ottenuto il blog, altrimenti si tratta di foto. Non è la soluzione più elegante, ma nel nostro caso specifico si rivela efficace.

Ti consigliamo anche