64 Gestire una chiamata AJAX in una PROMISE
Nella lezione precedente, abbiamo estratto i dati in JSON da un array php tramite una chiamata AJAX .
window.onload = function () { let xhr = new XMLHttpRequest(); xhr.open('GET', 'index.php'); xhr.send(); xhr.onreadystatechange = function () { if(xhr.readyState === 4 && xhr.status === 200) { let obj = JSON.parse(xhr.responseText); let ul = '<ul>'; ul += obj.map((book) => '<li>' + book.title + '</li>'); ul += '</ul>'; document.querySelector('#content').innerHTML = ul; } }; xhr.error = () => { "use strict"; alert('Problemi di risposta dal server'); } }
In questa lezione vedremo come effettuare la stessa operazione con. le promises. Con il precedente codice dovevamo aprire l’URL, verificare gli stati, gestire la parte dell’errore….
Iniziamo simulando JQuery istanziando un nuovo oggetto chiamato $ (se è installato JQuery potete chiamarlo $$)
let $ = {}
dentro questo oggetto dichiariamo un metodo chiamato Get che riceve l’url come parametro
let $ = { get : function (url) { } }
Dentro questo metodo Get andremo ad inserire tutto il codice della chiamata AJAX presente nella funzione di window.onload
let $ = { get : function (url) { let xhr = new XMLHttpRequest(); xhr.open('GET', 'index.php'); xhr.send(); xhr.onreadystatechange = function () { if(xhr.readyState === 4 && xhr.status === 200) { let obj = JSON.parse(xhr.responseText); let ul = '<ul>'; ul += obj.map((book) => '<li>' + book.title + '</li>'); ul += '</ul>'; document.querySelector('#content').innerHTML = ul; } }; xhr.error = () => { "use strict"; alert('Problemi di risposta dal server'); } } }
visto che la nuova funzione di get riceve come parametro un url, l’url ricevuto lo possiamo far passare direttamente al metodo open
xhr.open('GET', url);
Questo cambia il modo come viene gestita la chiamata GET, come viene passato l’url ora generato dinamicamente dal browser e inoltre cambiano anche i valori che vengono restituiti dalla promise, pertanto stanziamo una promise
let p = new Promise(function (resolve, reject) { }
mettiamo questa promise dentro la funzione get
let $ = { get : function (url) { let p = new Promise(function (resolve, reject) { }); ....codice AJAX }
Quindi abbiamo una funzione get che crea una promise, la quale si occuperà di effettuare i controlli e la chiamata AJAX. Quindi sposto tutto il codice dentro la promise
let $ = { get : function (url) { let p = new Promise(function (resolve, reject) { let xhr = new XMLHttpRequest(function () { }); xhr.open('GET', url); xhr.send(); xhr.onreadystatechange = function () { if(xhr.readyState === 4 && xhr.status === 200) { let obj = JSON.parse(xhr.responseText); let ul = '<ul>'; ul += obj.map((book) => '<li>' + book.title + '</li>'); ul += '</ul>'; document.querySelector('#content').innerHTML = ul; } }; xhr.error = () => { "use strict"; alert('Problemi di risposta dal server'); } }); } }
a questo punto dentro la promise troviamo l’apertura dell’url, l’invio della chiamata e la verifica dello stato xhr.onreadystatechange. Nella verifica dello stato se il controllo per lo stato 200 e il readyState 4 è andato a buon fine posso lanciare la risoluzione della promise con risolve e la risposta di xhr
if(xhr.readyState === 4 && xhr.status === 200) { resolve(xhr.responseText); }
Come risultato della funzione get ritorniamo la promise
return p;
nel caso ci fossero degli errori ritorniamo la reject della promise
xhr.error = () => { "use strict"; reject('Errore contattando il server'); }
Ricapitolando, abbiamo questo oggetto $ simil JQuery che ha il metodo get creato. Andremo ad utilizzare il metodo get nella funzione window.onload
window.onload = function () { $.get('index.php').then((res) => { "use strict"; let obj = JSON.parse(res); console.log(obj); }) }
a questo punto testiamo il tutto se funziona come prima. Ora visto che abbiamo inserito solo il metodo then che funziona solo se la promise è stata risolta, concateniamo il catch per catturare il reject
window.onload = function () { $.get('index.php').then((res) => { "use strict"; let obj = JSON.parse(res); console.log(obj); }).catch((erro) => console.log(erro)); }
Questa parte diventa molto più leggibile e fruibile.
Aggiungiamo un altro catch per gestire altri errori, tipo la porta errata, mettendo dentro l’if dello stato 4 un altro if dello stato 200
xhr.onreadystatechange = function () { if(xhr.readyState === 4 ) { if (xhr.status === 200) { resolve(xhr.responseText); } else { reject('Errore contattando il server'); } } };
Ricordo che le promise ritornano sempre un valore sia se è andato tutto a buon fine, quindi risolte oppure se c’è stato un rifiuto e quindi reject. Sta a noi gestire con catch e then le varie situazioni.
Quindi il codice finale rimane più leggibile, come regola generale ogni cosa che è possibile gestire con le promise, tipo le chiamate asincrone, va avvolta dalle promise in modo da ottenere un codice più pulito e facilmente manutenibile