jQuery: Zwróć dane po sukcesie wywołania ajaxowego

Mam coś takiego, gdzie jest to proste wywołanie do skryptu, który zwraca mi wartość, ciąg...

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

ale jeśli wywołam coś takiego jak to

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

więc jak mogę zwrócić wartość? poniższy kod również nie wydaje się działać...

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

      }
   });
   return data; 
}

Uwaga: Ta odpowiedź została napisana w lutym 2010 roku.
Zobacz aktualizacje z 2015, 2016 i 2017 roku na dole.
Nie możesz'zwrócić niczego z funkcji, która jest asynchroniczna. To, co możesz zwrócić, to obietnica. Wyjaśniłem, jak obietnice działają w jQuery w moich odpowiedziach na te pytania:

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

możesz napisać swoją funkcję testAjax w ten sposób:

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

Następnie możesz uzyskać swoją obietnicę w ten sposób:

var promise = testAjax();

Możesz przechowywać swoją obietnicę, możesz ją przekazywać, możesz używać jej jako argumentu w wywołaniach funkcji i możesz ją zwracać z funkcji, ale kiedy w końcu chcesz używać swoich danych, które są zwracane przez wywołanie AJAX, musisz to zrobić w ten sposób:

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

(Zobacz aktualizacje poniżej dla uproszczonej składni.). Jeśli Twoje dane są dostępne w tym momencie, wtedy ta funkcja zostanie wywołana natychmiast. Jeśli nie, to zostanie ona wywołana, gdy tylko dane będą dostępne. Cały sens robienia tego wszystkiego polega na tym, że twoje dane nie są dostępne natychmiast po wywołaniu $.ajax, ponieważ jest to funkcja asynchroniczna. Obietnice są miłą abstrakcją dla funkcji, aby powiedzieć: I can't return you the data because I don't have it yet and I don't want to block and make you wait so here's a promise instead and you'll be able to use it later, or to just give it to someone else and be done with it. Zobacz to [DEMO](http://jsfiddle.net/jW68r/). UPDATE (2015)

Obecnie (stan na marzec, 2015) jQuery Promises nie są zgodne ze specyfikacją Promises/A+, co oznacza, że mogą nie współpracować zbyt dobrze z innymi implementacjami Promises/A+ conformant. Jednak jQuery Promises w nadchodzącej wersji 3.x będzie zgodne ze specyfikacją Promises/A+ (podziękowania dla Benjamina Gruenbauma za zwrócenie na to uwagi). Obecnie (stan na maj, 2015) stabilne wersje jQuery to 1.x i 2.x.

To, co wyjaśniłem powyżej (w marcu, 2011) jest sposobem na użycie jQuery Deferred Objects do zrobienia czegoś asynchronicznie, co w kodzie synchronicznym zostałoby osiągnięte przez zwrócenie wartości. Ale synchroniczne wywołanie funkcji może zrobić dwie rzeczy - może albo zwrócić wartość (jeśli może) albo rzucić wyjątek (jeśli nie może'zwrócić wartości). Promises/A+ zajmuje się oboma tymi przypadkami użycia w sposób, który jest dość potężny jak obsługa wyjątków w kodzie synchronicznym. Wersja jQuery obsługuje odpowiednik zwracania wartości po prostu dobrze, ale odpowiednik złożonej obsługi wyjątków jest nieco problematyczny. W szczególności, całym sensem obsługi wyjątków w kodzie synchronicznym nie jest po prostu rezygnacja z miłą wiadomością, ale próba naprawienia problemu i kontynuowania wykonywania, lub ewentualnie ponowne rzucenie tego samego lub innego wyjątku dla innych części programu do obsługi. W kodzie synchronicznym masz stos wywołań. W kodzie asynchronicznym nie, a zaawansowana obsługa wyjątków wewnątrz obietnic, zgodnie ze specyfikacją Promises/A+, może naprawdę pomóc w pisaniu kodu, który będzie obsługiwał błędy i wyjątki w znaczący sposób, nawet dla złożonych przypadków użycia. O różnicach między jQuery a innymi implementacjami oraz o tym, jak przekonwertować obietnice jQuery na zgodne z Promises/A+, zobacz Coming from jQuery autorstwa Krisa Kowala et al. na wiki biblioteki Q oraz Promises arrive in JavaScript autorstwa Jake'a Archibalda na HTML5 Rocks.

Jak zwrócić prawdziwą obietnicę

Funkcja z mojego przykładu powyżej:

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

zwraca obiekt jqXHR, który jest jQuery Deferred Object. Aby zwrócić prawdziwą obietnicę, możesz zmienić ją na - używając metody z wiki Q:

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

lub, używając metody z artykułu HTML5 Rocks:

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

To Promise.resolve($.ajax(...)) jest również tym, co jest wyjaśnione w dokumentacji modułu promise i powinno działać z ES6 Promise.resolve(). Aby używać obietnic ES6 dzisiaj, możesz użyć es6-promise module's polyfill() Jake'a Archibalda. Aby zobaczyć, gdzie możesz użyć ES6 Promises bez polyfill, zobacz: Can I use: Promises. Aby uzyskać więcej informacji zobacz:

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

można napisać:

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

lub korzystając z API Promises/A+:

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

Pamiętaj, aby zawsze używać handlerów odrzuceń albo z:

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

lub z:

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

Zobacz tę odpowiedź, aby zobaczyć, dlaczego zawsze powinieneś używać handlarzy odrzuceniem z obietnicami:

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

Nie każda przeglądarka obsługuje tę składnię, ale są pewne przypadki, kiedy jesteś pewien, na jakiej przeglądarce będzie działać twój kod - np. kiedy piszesz Chrome extension, Firefox Add-on, lub aplikację desktopową używającą Electron, NW.js lub AppJS (zobacz ta odpowiedź po szczegóły). Aby uzyskać wsparcie dla funkcji strzałek, zobacz:

  • Istnieje jeszcze nowsza składnia w tej chwili zwana funkcjami async z nowym słowem kluczowym await, które zamiast tego kodu:
functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

pozwala napisać:

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

Możesz go użyć tylko wewnątrz funkcji utworzonej za pomocą słowa kluczowego async. Aby uzyskać więcej informacji, zobacz:

Komentarze (9)
Rozwiązanie

Jedynym sposobem na zwrócenie danych z funkcji byłoby wykonanie wywołania synchronicznego zamiast asynchronicznego, ale to spowodowałoby zamrożenie przeglądarki podczas oczekiwania na odpowiedź.

Możesz przekazać funkcję wywołania zwrotnego, która obsłuży wynik:

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

Wywołaj ją w ten sposób:

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

Zobacz przykład w jquery docs: http://api.jquery.com/jQuery.ajax/ (około 2/3 strony)

Być może będziesz szukał następującego kodu:

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

Ta sama strona...niżej.

Komentarze (0)