Come posso gestire una risposta asincrona in Ajax?

Come posso gestire una risposta asincrona in Ajax?

Utilizzare le comunicazioni asincrone tra client (il browser) e server significa procedere con il codice anche se la risposta del server non è ancora arrivata.

Ho una funzione prova() che fa una richiesta Ajax. Come posso restituire la risposta da parte di prova()?
Ho provato a restituire il valore dal callback di successo e ad assegnare la risposta a una variabile locale all’interno della funzione e restituire quella, ma nessuno di questi modi restituisce effettivamente la risposta.

function prova() {
    var result;
    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- Qui il risultato arriva
        }
    });
    return result;
}
var result = prova(); // Qui ottengo sempre il risultato 'undefined'.

Eh… Houston! Abbiamo un problema!

Il problema

La A in Ajax sta per asincrono.
Ciò significa che la ricezione della risposta viene portata fuori dal normale flusso di esecuzione.

Nel tuo esempio, il comando $.ajax esegue al suo interno alcune operazioni e ci si aspetterebbe che, prima di eseguire l’istruzione successiva, attenda di ottenere il risultato di tali operazioni. Ma allora perché mai utilizzare Ajax?
Utilizzare le comunicazioni asincrone tra client (il browser) e server significa procedere con il codice anche se la risposta del server non è ancora arrivata.
Tutto ciò dovrebbe chiarirti il motivo per cui l’istruzione return result; non restituisca nessun valore. Infatti, proprio a causa delle comunicazioni asincrone, quando il codice arriva all’istruzione return result, la variabile result potrebbe non essere stata ancora avvalorata. Considerando i tempi di latenza delle comunicazioni tra client e server result non sarà quasi mai avvalorata.
Facciamo un esempio di codice sincrono e uno di codice asincrono per provare a comprendere meglio.

Sincrono

Immagina di fare una telefonata ad un amico e chiedergli di cercare qualcosa per te. Anche se potrebbe volerci un po’, tu aspetti al telefono e fissi nello spazio vuoto finché il tuo amico ti darà la risposta di cui avevi bisogno. Questo è ciò che accade quando si effettua una chiamata di funzione contenente un codice “normale”, cioè sincrono.

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}
var item = findItem();
// Do something with item
doSomethingElse();

Anche se findItem() potrebbe impiegare molto tempo per l’esecuzione, qualsiasi codice verrà dopo l’istruzione var item = findItem(); deve aspettare fino a quando la funzione non restituisce il risultato.

Asincrono

Immagina ora di chiamare di nuovo il tuo amico per lo stesso motivo, ma questa volta gli dici che hai fretta e gli chiedi di richiamarti non appena entrerà in possesso di quanto gli hai richiesto. Riattacca, esci di casa e fai qualunque cosa tu abbia pianificato di fare. Una volta che il tuo amico ti avrà richiamato, avrai la risposta che stavi aspettando e la potrai utilizzare come meglio credi (sebbene, nel frattempo, tu abbia svolto altri compiti!).
Questo è esattamente ciò che accade quando fai una richiesta Ajax o asincorna.

findItem(function(item) {
    // Do something with item
});
doSomethingElse();

Invece di attendere la risposta, l’esecuzione continua immediatamente e viene eseguita la dichiarazione dopo la chiamata Ajax. Per gestire la risposta, quando arriverà, si fornisce una funzione da chiamare appena ricevuta la risposta attesa.

Soluzione

Il tuo problema può quindi essere risolto in modo molto semplice.
Utilizza la funzione associata al success: per scrivere il codice che vuoi venga eseguito quando arriva la risposta dal server.

function prova() {
    var result;
    $.ajax({
        url: '...',
        success: function(response) {
            // QUI DENTRO SCRIVI IL CODICE CHE DOVRA' ESSERE
            // ESEGUITO QUANDO IL SERVER RISPONDERA'
        }
    });
}

Questa naturalmente non è l’unica soluzione possibile, ma di certo funzionerà 🙂