jQuery: Palauta tiedot ajax-kutsun onnistumisen jälkeen

Minulla on jotain tällaista, jossa on yksinkertainen kutsu skriptiin, joka antaa minulle takaisin arvon, merkkijonon...

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

mutta jos kutsun jotain tällaista

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

niin miten voin palauttaa arvon? myöskään alla oleva koodi ei näytä toimivan...

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

      }
   });
   return data; 
}

Huom: Tämä vastaus on kirjoitettu helmikuussa 2010.
Katso päivitykset vuosilta 2015, 2016 ja 2017 alareunasta.
Asynkronisesta funktiosta ei voi palauttaa mitään. Se, mitä voit palauttaa, on lupaus. Selitin vastauksissani näihin kysymyksiin, miten lupaukset toimivat jQueryssä:

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

voit kirjoittaa testAjax-funktion näin:

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

Sitten saat lupauksesi näin:

var promise = testAjax();

Voit tallentaa lupauksesi, voit välittää sen eteenpäin, voit käyttää sitä argumenttina funktiokutsuissa ja voit palauttaa sen funktioista, mutta kun lopulta haluat käyttää AJAX-kutsun palauttamia tietojasi, sinun on tehtävä se näin:

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

(Yksinkertaistettu syntaksi on päivityksissä alla.) Jos tietosi ovat käytettävissä tässä vaiheessa, tämä funktio kutsutaan välittömästi. Jos se ei ole, se kutsutaan heti, kun tiedot ovat saatavilla. Koko tämän tekemisen tarkoitus on, että tietosi eivät ole käytettävissä heti $.ajax-kutsun jälkeen, koska se on asynkroninen. Lupaukset on mukava abstraktio funktioille sanoa: En voi palauttaa sinulle dataa, koska minulla ei ole sitä vielä, enkä halua estää sinua odottamasta, joten tässä on sen sijaan lupaus, jonka avulla voit käyttää sitä myöhemmin, tai antaa sen jollekin toiselle ja hoitaa asian. Katso tämä [DEMO](http://jsfiddle.net/jW68r/). PÄIVITYS (2015)

Tällä hetkellä (maaliskuussa 2015) jQuery Promises ei ole yhteensopiva Promises/A+ -spesifikaation kanssa, mikä tarkoittaa, että ne eivät välttämättä toimi kovin hyvin yhteistyössä muiden Promises/A+ -yhteensopivien toteutusten kanssa. Tulevassa versiossa 3.x jQuery Promises tulee kuitenkin olemaan yhteensopiva Promises/A+-spesifikaation kanssa (kiitos Benjamin Gruenbaumille, joka huomautti asiasta). Tällä hetkellä (toukokuussa 2015) jQueryn vakaat versiot ovat 1.x ja 2.x.

Edellä (maaliskuussa 2011) selitin, että jQuery Deferred Objects on tapa käyttää jQuery Deferred Objects tekemään asynkronisesti jotakin, joka synkronisessa koodissa saavutettaisiin palauttamalla arvo. Mutta synkroninen funktiokutsu voi tehdä kaksi asiaa - se voi joko palauttaa arvon (jos se voi) tai heittää poikkeuksen (jos se ei voi palauttaa arvoa). Promises/A+ ratkaisee molemmat näistä käyttötapauksista tavalla, joka on melko lailla yhtä tehokas kuin poikkeusten käsittely synkronisessa koodissa. JQuery-versio käsittelee arvon palauttamista vastaavan tehtävän hienosti, mutta monimutkaisten poikkeusten käsittely on hieman ongelmallista. Poikkeuskäsittelyn tarkoitus synkronisessa koodissa ei ole vain luovuttaa mukavan viestin kanssa, vaan yrittää korjata ongelma ja jatkaa suoritusta tai mahdollisesti heittää sama tai erilainen poikkeus uudelleen ohjelman muiden osien käsiteltäväksi. Synkronisessa koodissa on kutsupino. Asynkronisessa kutsussa sitä ei ole, ja Promises/A+ -spesifikaation edellyttämä kehittynyt poikkeuskäsittely lupausten sisällä voi todella auttaa sinua kirjoittamaan koodia, joka käsittelee virheet ja poikkeukset mielekkäällä tavalla myös monimutkaisissa käyttötapauksissa. Erilaisuuksista jQueryn ja muiden toteutusten välillä sekä siitä, miten jQueryn lupaukset muunnetaan Promises/A+-yhteensopiviksi, on kerrottu Kris Kowalin ym. artikkelissa Coming from jQuery Q-kirjaston wikissä ja Jake Archibaldin artikkelissa Promises arrive in JavaScript HTML5 Rocksissa.

Miten palauttaa oikea lupaus

Yllä olevan esimerkkini funktio:

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

palauttaa jqXHR-olion, joka on jQueryn Deferred Object. Jotta se palauttaisi todellisen lupauksen, voit muuttaa sen muotoon - käyttämällä Q-wikin metodia:

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

tai käyttämällä HTML5 Rocks -artikkelin metodia:

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

Tämä Promise.resolve($.ajax(...)) on myös se, mitä selitetään promise-moduulin dokumentaatiossa ja sen pitäisi toimia ES6 Promise.resolve() kanssa. Jos haluat käyttää ES6-lupauksia nykyään, voit käyttää es6-promise-moduuli'n polyfill() Jake Archibaldin tekemää es6-promise-moduuli'n polyfill(). Jos haluat nähdä, missä voit käyttää ES6 Promisesia ilman polyfilliä, katso: Can I use: Promises. Lisätietoja on osoitteessa:

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

voit kirjoittaa:

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

tai käyttämällä Promises/A+ API:ta:

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

Muista aina käyttää hylkäyskäsittelijöitä joko:

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

tai kanssa:

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

Katso tästä vastauksesta, miksi hylkäyskäsittelijöitä kannattaa aina käyttää lupausten kanssa:

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

Kaikki selaimet eivät vielä tue tätä syntaksia, mutta on tiettyjä tapauksia, joissa olet varma, millä selaimella koodisi toimii - esimerkiksi kirjoittaessasi Chrome-laajennusta, Firefox-lisäosaa tai työpöytäsovellusta, jossa käytetään Electronia, NW.js:ää tai AppJS:ää (katso lisätietoja tästä vastauksesta). Nuolifunktioiden tuesta ks:

  • Tällä hetkellä on olemassa vielä uudempi syntaksi nimeltä async-funktiot, jossa on uusi await-avainsana, joka tämän koodin sijaan:
functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

voit kirjoittaa:

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

Voit käyttää sitä vain async-avainsanalla luodun funktion sisällä. Lisätietoja on osoitteessa:

Kommentit (9)
Ratkaisu

Ainoa tapa palauttaa tiedot funktiosta olisi tehdä synkroninen kutsu asynkronisen kutsun sijasta, mutta se jähmettäisi selaimen odottaessaan vastausta.

Voit välittää takaisinsoittofunktion, joka käsittelee tuloksen:

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

Kutsu sitä näin:

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.
Kommentit (7)

Katso jquery docs -esimerkki: http://api.jquery.com/jQuery.ajax/ (noin 2/3 sivusta)

Saatat etsiä seuraavaa koodia:

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

Sama sivu... alempana.

Kommentit (0)