jQuery: Restituire i dati dopo il successo della chiamata ajax

Ho qualcosa del genere, dove è una semplice chiamata a uno script che mi restituisce un valore, una stringa.

function testAjax() {
    $.ajax({
      url: "getvalue.php",  
      success: function(data) {
         return data; 
      }
   });
}

ma se chiamo qualcosa come questo

var output = testAjax(svar);  // output will be undefined...

come posso restituire il valore? anche il codice seguente non sembra funzionare...

function testAjax() {
    $.ajax({
      url: "getvalue.php",  
      success: function(data) {

      }
   });
   return data; 
}

Nota: Questa risposta è stata scritta nel febbraio 2010.
Vedi gli aggiornamenti del 2015, 2016 e 2017 in fondo.
Non si può restituire nulla da una funzione asincrona. Quello che si può restituire è una promessa. Ho spiegato come funzionano le promesse in jQuery nelle mie risposte a queste domande:

function testAjax() {
  $.ajax({
    url: "getvalue.php",  
    success: function(data) {
      return data; 
    }
  });
}

puoi scrivere la tua funzione testAjax come questa:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}

Poi puoi ottenere la tua promessa in questo modo:

var promise = testAjax();

Puoi memorizzare la tua promessa, puoi passarla in giro, puoi usarla come argomento nelle chiamate di funzione e puoi restituirla dalle funzioni, ma quando finalmente vuoi usare i tuoi dati restituiti dalla chiamata AJAX, devi farlo in questo modo:

promise.success(function (data) {
  alert(data);
});

(Vedi gli aggiornamenti qui sotto per una sintassi semplificata.) Se i vostri dati sono disponibili a questo punto, allora questa funzione sarà invocata immediatamente. Se non lo sono, sarà invocata non appena i dati saranno disponibili. L'intero punto di fare tutto questo è che i vostri dati non sono disponibili immediatamente dopo la chiamata a $.ajax perché è asincrona. Le promesse sono una bella astrazione per le funzioni per dire: Non posso restituirti i dati perché non li ho ancora e non voglio bloccarti e farti aspettare, quindi eccoti una promessa e potrai usarla più tardi, o semplicemente darla a qualcun altro e farla finita. Vedi questo [DEMO](http://jsfiddle.net/jW68r/). AGGIORNAMENTO (2015)

Attualmente (a marzo 2015) i Promises di jQuery non sono compatibili con la specifica Promises/A+ il che significa che potrebbero non cooperare molto bene con altre implementazioni Promises/A+ conformant. Tuttavia jQuery Promises nella prossima versione 3.x sarà compatibile con la specifica Promises/A+ (grazie a Benjamin Gruenbaum per averlo segnalato). Attualmente (a maggio 2015) le versioni stabili di jQuery sono 1.x e 2.x.

Quello che ho spiegato sopra (nel marzo 2011) è un modo per usare jQuery Deferred Objects per fare qualcosa in modo asincrono che nel codice sincrono sarebbe stato ottenuto restituendo un valore. Ma una chiamata di funzione sincrona può fare due cose - può restituire un valore (se può) o lanciare un'eccezione (se non può restituire un valore). Promises/A+ affronta entrambi questi casi d'uso in un modo che è abbastanza potente come la gestione delle eccezioni nel codice sincrono. La versione jQuery gestisce bene l'equivalente della restituzione di un valore, ma l'equivalente della gestione delle eccezioni complesse è un po' problematica. In particolare, l'intero punto della gestione delle eccezioni nel codice sincrono non è solo arrendersi con un bel messaggio, ma cercare di risolvere il problema e continuare l'esecuzione, o eventualmente rilanciare la stessa o una diversa eccezione per altre parti del programma da gestire. Nel codice sincrono si ha uno stack di chiamate. Nella chiamata asincrona no, e la gestione avanzata delle eccezioni all'interno delle promesse come richiesto dalla specifica Promises/A+ può davvero aiutare a scrivere codice che gestirà errori ed eccezioni in modo significativo anche per casi d'uso complessi. Per le differenze tra jQuery e altre implementazioni, e come convertire le promesse di jQuery in Promises/A+ compliant, vedere Coming from jQuery di Kris Kowal et al. sul wiki della libreria Q e Promises arrive in JavaScript di Jake Archibald su HTML5 Rocks.

Come restituire una vera promessa

La funzione del mio esempio sopra:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}

restituisce un oggetto jqXHR, che è un jQuery Deferred Object. Per far sì che restituisca una vera promessa, puoi cambiarla in - usando il metodo dal wiki di Q:

function testAjax() {
  return Q($.ajax({
      url: "getvalue.php"
  }));
}

oppure, usando il metodo dall'articolo HTML5 Rocks:

function testAjax() {
  return Promise.resolve($.ajax({
      url: "getvalue.php"
  }));
}

Questo Promise.resolve($.ajax(...)) è anche quello che è spiegato nella documentazione del modulo promise e dovrebbe funzionare con ES6 Promise.resolve(). Per usare le Promesse ES6 oggi potete usare es6-promise module's polyfill() di Jake Archibald. Per vedere dove puoi usare le Promesse ES6 senza il polyfill, vedi: Posso usare: Promises. Per ulteriori informazioni vedere:

promise.success(function (data) {
  alert(data);
});

si può scrivere:

promise.success(data => alert(data));

o usando l'API Promises/A+:

promise.then(data => alert(data));

Ricorda di usare sempre gestori di rifiuto o con:

promise.then(data => alert(data), error => alert(error));

o con:

promise.then(data => alert(data)).catch(error => alert(error));

Vedi questa risposta per vedere perché dovresti sempre usare i gestori di rifiuto con le promesse:

promise.then(data => alert("x is " + data.x));

Non tutti i browser supportano ancora questa sintassi, ma ci sono alcuni casi in cui sei sicuro su quale browser il tuo codice verrà eseguito - ad esempio quando scrivi una estensione per Chrome, un Add-on per Firefox, o un'applicazione desktop utilizzando Electron, NW.js o AppJS (vedi questa risposta per dettagli). Per il supporto delle funzioni di freccia, vedere:

  • C'è una sintassi ancora più nuova ora chiamata funzioni async con una nuova parola chiave await che invece di questo codice:
functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

ti permette di scrivere:

try {
    let data = await functionReturningPromise();
    console.log('Data:', data);
} catch (error) {
    console.log('Error:', error);
}

Si può usare solo all'interno di una funzione creata con la parola chiave async. Per maggiori informazioni, vedere:

Commentari (9)
Soluzione

L'unico modo per restituire i dati dalla funzione sarebbe fare una chiamata sincrona invece di una chiamata asincrona, ma questo bloccherebbe il browser mentre aspetta la risposta.

Potete passare una funzione di callback che gestisce il risultato:

function testAjax(handleData) {
  $.ajax({
    url:"getvalue.php",  
    success:function(data) {
      handleData(data); 
    }
  });
}

Chiamatela così:

testAjax(function(output){
  // here you use the output
});
// Note: the call won't wait for the result,
// so it will continue with the code here while waiting.
Commentari (7)

Vedere l'esempio di jquery docs: http://api.jquery.com/jQuery.ajax/ (circa 2/3 della pagina)

Potresti cercare il seguente codice:

    $.ajax({
     url: 'ajax/test.html',
     success: function(data) {
     $('.result').html(data);
     alert('Load was performed.');
   }
});

Stessa pagina... più in basso.

Commentari (0)