jQuery: Vrátenie údajov po úspešnom ajaxovom volaní

Mám niečo podobné, kde je jednoduché volanie skriptu, ktorý mi vráti hodnotu, reťazec.

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

ale ak zavolám niečo také

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

tak ako môžem vrátiť hodnotu? zdá sa, že ani nižšie uvedený kód nefunguje...

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

      }
   });
   return data; 
}

Poznámka: Táto odpoveď bola napísaná vo februári 2010.
Pozrite si aktualizácie z rokov 2015, 2016 a 2017 na konci článku.
Z funkcie, ktorá je asynchrónna, nemôžete'nič vrátiť. To, čo môžete vrátiť, je prísľub. Ako fungujú sľuby v jQuery, som vysvetlil v odpovediach na tieto otázky:

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

môžete svoju funkciu testAjax napísať takto:

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

Potom môžete získať svoj prísľub takto:

var promise = testAjax();

Svoj prísľub môžete uložiť, môžete ho posielať ďalej, môžete ho použiť ako argument vo volaniach funkcií a môžete ho vrátiť z funkcií, ale keď chcete konečne použiť svoje údaje, ktoré sa vrátia z volania AJAX, musíte to urobiť takto:

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

(Zjednodušenú syntax nájdete v aktualizáciách nižšie.) Ak sú vaše údaje v tomto okamihu k dispozícii, potom sa táto funkcia vyvolá okamžite. Ak nie sú, potom sa vyvolá hneď, ako budú údaje k dispozícii. Celý zmysel tohto všetkého spočíva v tom, že vaše údaje nie sú k dispozícii okamžite po volaní $.ajax, pretože je asynchrónny. Prísľuby sú peknou abstrakciou pre funkcie, ktoré sa dajú povedať: Nemôžem vám vrátiť údaje, pretože ich ešte nemám a nechcem ich blokovať a nechať vás čakať, takže namiesto toho tu máte prísľub a budete ich môcť použiť neskôr, alebo ich jednoducho dať niekomu inému a skončiť s tým. Pozri tento [DEMO](http://jsfiddle.net/jW68r/). UPDATE (2015)

V súčasnosti (od marca 2015) nie sú jQuery Promises kompatibilné so špecifikáciou Promises/A+, čo znamená, že nemusia veľmi dobre spolupracovať s inými implementáciami vyhovujúcimi Promises/A+. Avšak jQuery Promises v nadchádzajúcej verzii 3.x budú kompatibilné so špecifikáciou Promises/A+ (vďaka Benjaminovi Gruenbaumovi za upozornenie). V súčasnosti (od mája 2015) sú stabilné verzie jQuery 1.x a 2.x.

To, čo som vysvetlil vyššie (v marci 2011), je spôsob, ako použiť jQuery Deferred Objects na asynchrónne vykonanie niečoho, čo by sa v synchrónnom kóde dosiahlo vrátením hodnoty. Synchrónne volanie funkcie však môže urobiť dve veci - buď vráti hodnotu (ak ju môže vrátiť), alebo vyhodí výnimku (ak hodnotu vrátiť nemôže). Promises/A+ rieši oba tieto prípady použitia spôsobom, ktorý je v podstate rovnako výkonný ako spracovanie výnimiek v synchrónnom kóde. Verzia jQuery zvláda ekvivalent vrátenia hodnoty v poriadku, ale ekvivalent komplexného spracovania výnimiek je trochu problematický. Celý zmysel spracovania výnimiek v synchrónnom kóde nespočíva najmä v tom, že sa len vzdá s peknou správou, ale snaží sa problém odstrániť a pokračovať vo vykonávaní, prípadne znovu vyhodiť tú istú alebo inú výnimku, ktorú majú spracovať iné časti programu. V synchrónnom kóde máte zásobník volaní. V asynchrónnom volaní ho nemáte'a pokročilé spracovanie výnimiek vo vnútri sľubov, ako to vyžaduje špecifikácia Promises/A+, vám môže skutočne pomôcť napísať kód, ktorý bude zmysluplne spracovávať chyby a výnimky aj pre zložité prípady použitia. Rozdiely medzi jQuery a inými implementáciami a spôsob konverzie sľubov jQuery na sľuby vyhovujúce špecifikácii Promises/A+ nájdete v publikáciách Coming from jQuery od Krisa Kovala a ďalších na wiki knižnice Q a Promises arrive in JavaScript od Jakea Archibalda na HTML5 Rocks.

Ako vrátiť skutočný sľub

Funkcia z môjho príkladu vyššie:

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

vráti objekt jqXHR, čo je jQuery Deferred Object. Ak chcete, aby vrátila skutočný sľub, môžete ho zmeniť na - pomocou metódy z Q wiki:

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

alebo pomocou metódy z článku HTML5 Rocks:

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

Tento Promise.resolve($.ajax(...)) je tiež to, čo je vysvetlené v dokumentácii modulu promise a malo by to fungovať s ES6 Promise.resolve(). Na použitie ES6 Promises dnes môžete použiť es6-promise modul'polyfill() od Jakea Archibalda. Ak chcete zistiť, kde môžete použiť ES6 Promises bez polyfill, pozrite si: Can I use: Promises. Ďalšie informácie nájdete na stránke:

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

môžete napísať:

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

alebo pomocou API Promises/A+:

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

Nezabudnite vždy používať obsluhy odmietnutia buď s:

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

alebo s:

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

V tejto odpovedi sa dozviete, prečo by ste mali vždy používať obsluhy odmietnutia s prísľubmi:

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

Túto syntax zatiaľ nepodporujú všetky prehliadače, ale existujú určité prípady, keď'ste si istí, v akom prehliadači bude váš kód bežať - napr. pri písaní rozšírenia pre Chrome, doplnku pre Firefox alebo desktopovej aplikácie pomocou Electronu, NW.js alebo AppJS (podrobnosti nájdete v tejto odpovedi). Pokiaľ ide o podporu šípkových funkcií, pozrite si:

  • V súčasnosti existuje ešte novšia syntax s názvom asynchrónne funkcie s novým kľúčovým slovom await, ktoré namiesto tohto kódu:
functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

umožňuje napísať:

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

Môžete ho použiť len vo vnútri funkcie vytvorenej pomocou kľúčového slova async. Viac informácií nájdete na:

Komentáre (9)
Riešenie

Jediný spôsob, ako vrátiť údaje z funkcie, by bolo synchrónne volanie namiesto asynchrónneho volania, ale to by prehliadač počas čakania na odpoveď zamrzol.

Môžete odovzdať funkciu spätného volania, ktorá spracuje výsledok:

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

Volajte ju takto:

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.
Komentáre (7)

Pozrite si príklad v dokumentoch jquery: http://api.jquery.com/jQuery.ajax/ (asi 2/3 stránky)

Možno hľadáte nasledujúci kód:

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

Tá istá stránka... nižšie.

Komentáre (0)