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/). ΕΝΗΜΕΡΩΣΗ (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 et al. στο wiki της βιβλιοθήκης Q και Promises arrive in JavaScript από τον Jake Archibald στο HTML5 Rocks.

Πώς να επιστρέψετε μια πραγματική υπόσχεση

Η συνάρτηση από το παραπάνω παράδειγμά μου:

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

επιστρέφει ένα αντικείμενο jqXHR, το οποίο είναι ένα Deferred Object της jQuery. Για να την κάνετε να επιστρέψει μια πραγματική υπόσχεση, μπορείτε να την αλλάξετε σε - χρησιμοποιώντας τη μέθοδο από το Q wiki:

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 χωρίς το polyfill, δείτε: Can I use: 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, ή μια desktop εφαρμογή που χρησιμοποιεί Electron, NW.js ή AppJS (δείτε αυτή την απάντηση για λεπτομέρειες). Για την υποστήριξη των συναρτήσεων βέλους, βλ:

  • Υπάρχει μια ακόμα νεότερη σύνταξη αυτή τη στιγμή που ονομάζεται async functions με μια νέα λέξη-κλειδί 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)