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