jQuery: Връщане на данни след успех на ajax повикването

Имам нещо подобно, което представлява просто извикване на скрипт, който ми връща стойност, низ.

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

но ако извикам нещо като това

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

как мога да върна стойността? изглежда, че и кодът по-долу не работи...

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

      }
   });
   return data; 
}

Забележка: Този отговор е написан през февруари 2010 г.
Вижте актуализациите от 2015 г., 2016 г. и 2017 г. в долната част.
Не можете'да върнете нищо от функция, която е асинхронна. Това, което можете да върнете, е обещание. Обясних как работят обещанията в jQuery в отговорите си на тези въпроси:

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

можете да напишете функцията си testAjax по следния начин:

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

Тогава можете да получите обещанието си по следния начин:

var promise = testAjax();

Можете да съхранявате обещанието си, можете да го предавате, можете да го използвате като аргумент при извикване на функции и можете да го връщате от функции, но когато най-накрая искате да използвате данните си, върнати от AJAX извикването, трябва да го направите по следния начин:

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

(Вижте актуализациите по-долу за опростен синтаксис.) Ако данните ви са налични в този момент, тази функция ще бъде извикана незабавно. Ако не са, тогава тя ще бъде извикана веднага щом данните са налични. Смисълът на всичко това е, че данните ви не са налични веднага след извикването на $.ajax, защото то е асинхронно. Обещанията са хубава абстракция за функциите, които могат да кажат: Не мога да ви върна данните, защото все още не разполагам с тях, а не искам да блокирам и да ви карам да чакате, така че вместо това ви предлагам обещание, което ще можете да използвате по-късно, или просто да ги дадете на някой друг и да приключите с тях. Вижте това [DEMO](http://jsfiddle.net/jW68r/). UPDATE (2015 Г.)

Понастоящем (към март 2015 г.) jQuery Promises не са съвместими със спецификацията Promises/A+, което означава, че те може да не си сътрудничат много добре с други имплементации, съответстващи на Promises/A+. Въпреки това jQuery Promises в предстоящата версия 3.x ще бъдат съвместими със спецификацията Promises/A+ (благодаря на Benjamin Gruenbaum за това, че го посочи). Понастоящем (към май 2015 г.) стабилните версии на jQuery са 1.x и 2.x.

Това, което обясних по-горе (през март 2011 г.), е начин да се използват jQuery Deferred Objects, за да се направи нещо асинхронно, което в синхронен код би се постигнало чрез връщане на стойност. Но едно синхронно извикване на функция може да направи две неща - то може или да върне стойност (ако може), или да хвърли изключение (ако не може да върне стойност). Promises/A+ адресира и двата случая на употреба по начин, който е почти толкова мощен, колкото обработката на изключения в синхронен код. Версията на jQuery се справя отлично с еквивалента на връщане на стойност, но еквивалентът на сложна обработка на изключение е малко проблематичен. По-специално, целият смисъл на обработката на изключения в синхронен код не е просто да се откажеш с хубаво съобщение, а да се опиташ да решиш проблема и да продължиш изпълнението, или евентуално да хвърлиш отново същото или друго изключение, което да бъде обработено от други части на програмата. В синхронния код имате стек от повиквания. В асинхронното извикване нямате и усъвършенстваната обработка на изключенията вътре в обещанията ви, както се изисква от спецификацията Promises/A+, може наистина да ви помогне да напишете код, който ще обработва грешките и изключенията по смислен начин дори за сложни случаи на употреба. За разликите между jQuery и други имплементации и за това как да преобразувате обещанията на jQuery в съвместими с Promises/A+ вижте Coming from jQuery от Kris Kowal и др. в уикито на библиотеката Q и Promises arrive in JavaScript от Jake Archibald в HTML5 Rocks.

Как да върнем истинско обещание

Функцията от примера ми по-горе:

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

връща обект jqXHR, който е jQuery Deferred Object. За да я накарате да върне истинско обещание, можете да я промените на -, като използвате метода от уикипедия Q:

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

или, като използвате метода от статията HTML5 Rocks:

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

Този Promise.resolve($.ajax(...)) също е това, което е обяснено в документацията на модула promise и би трябвало да работи с ES6 Promise.resolve(). За да използвате ES6 Promises днес, можете да използвате es6-promise module's polyfill() на Jake Archibald. За да видите къде можете да използвате ES6 Promises без полифила, вижте: Мога ли да използвам: Promises. За повече информация вижте:

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

можете да напишете:

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

или като използвате API Promises/A+:

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

Не забравяйте винаги да използвате обработчици за отхвърляне или с:

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

или с:

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

Вижте този отговор, за да разберете защо винаги трябва да използвате обработчици за отхвърляне с обещания:

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

Все още не всеки браузър поддържа този синтаксис, но има някои случаи, когато сте сигурни на кой браузър ще работи кодът ви - например когато пишете разширение за Chrome, добавка за Firefox или десктоп приложение, използващо Electron, NW.js или AppJS (за подробности вижте този отговор). За поддръжката на функции със стрелки вижте:

  • В момента има още по-нов синтаксис, наречен асинхронни функции, с нова ключова дума await, която вместо този код:
functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

ви позволява да напишете:

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

Можете да я използвате само вътре във функция, създадена с ключовата дума async. За повече информация вижте:

Коментари (9)
Решение

Единственият начин за връщане на данните от функцията би бил да се направи синхронно извикване вместо асинхронно, но това би замразило браузъра, докато чака отговора.

Можете да подадете функция за обратно извикване, която обработва резултата:

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

Извикайте я по следния начин:

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.
Коментари (7)

Вижте примера в документацията на jquery: http://api.jquery.com/jQuery.ajax/ (около 2/3 от страницата)

Може би търсите следния код:

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

Същата страница... по-надолу.

Коментари (0)