Περισσότερα
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;
}
444
3
Σημείωση: Αυτή η απάντηση γράφτηκε τον Φεβρουάριο του 2010.
Δείτε ενημερώσεις από το 2015, 2016 και 2017 στο κάτω μέρος. Δεν μπορείτε να επιστρέψετε τίποτα από μια συνάρτηση που είναι ασύγχρονη. Αυτό που μπορείτε να επιστρέψετε είναι μια υπόσχεση. Εξήγησα πώς λειτουργούν οι υποσχέσεις στην jQuery στις απαντήσεις μου σε αυτές τις ερωτήσεις:
μπορείτε να γράψετε τη συνάρτηση testAjax σας ως εξής:
Στη συνέχεια, μπορείτε να πάρετε την υπόσχεσή σας ως εξής:
Μπορείτε να αποθηκεύσετε την υπόσχεσή σας, μπορείτε να τη μεταβιβάσετε, μπορείτε να τη χρησιμοποιήσετε ως όρισμα σε κλήσεις συναρτήσεων και μπορείτε να την επιστρέψετε από συναρτήσεις, αλλά όταν τελικά θέλετε να χρησιμοποιήσετε τα δεδομένα σας που επιστρέφονται από την κλήση AJAX, πρέπει να το κάνετε ως εξής:
(Δείτε τις ενημερώσεις παρακάτω για την απλοποιημένη σύνταξη.) Εάν τα δεδομένα σας είναι διαθέσιμα σε αυτό το σημείο, τότε αυτή η συνάρτηση θα κληθεί αμέσως. Εάν δεν είναι'τότε θα κληθεί μόλις τα δεδομένα είναι διαθέσιμα. Το όλο νόημα που γίνεται όλο αυτό είναι ότι τα δεδομένα σας δεν είναι διαθέσιμα αμέσως μετά την κλήση της $.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.
Πώς να επιστρέψετε μια πραγματική υπόσχεση
Η συνάρτηση από το παραπάνω παράδειγμά μου:
επιστρέφει ένα αντικείμενο jqXHR, το οποίο είναι ένα Deferred Object της jQuery. Για να την κάνετε να επιστρέψει μια πραγματική υπόσχεση, μπορείτε να την αλλάξετε σε - χρησιμοποιώντας τη μέθοδο από το Q wiki:
ή, χρησιμοποιώντας τη μέθοδο από το άρθρο HTML5 Rocks:
Αυτό το
Promise.resolve($.ajax(...))
είναι επίσης αυτό που εξηγείται στην τεκμηρίωση της ενότηταςpromise
και θα πρέπει να λειτουργεί με το ES6Promise.resolve()
. Για να χρησιμοποιήσετε τις ES6 Promises σήμερα μπορείτε να χρησιμοποιήσετε το es6-promise module'spolyfill()
από τον Jake Archibald. Για να δείτε πού μπορείτε να χρησιμοποιήσετε τις ES6 Promises χωρίς το polyfill, δείτε: Can I use: Promises. Για περισσότερες πληροφορίες βλ:Το μέλλον της jQuery
Οι μελλοντικές εκδόσεις της jQuery (ξεκινώντας από την έκδοση 3.x - οι τρέχουσες σταθερές εκδόσεις από τον Μάιο του 2015 είναι οι 1.x και 2.x) θα είναι συμβατές με την Promises/A+ specification (ευχαριστούμε τον Benjamin Gruenbaum για την επισήμανση στα σχόλια). "Δύο αλλαγές που έχουμε ήδη αποφασίσει είναι η συμβατότητα Promise/A+ για την υλοποίηση Deferred [...]" (jQuery 3.0 and the future of Web development). Για περισσότερες πληροφορίες βλ: jQuery 3.0: The Next Generations του Dave Methvin και jQuery 3.0: More interoperability, less Internet Explorer του Paul Krill.
Ενδιαφέρουσες ομιλίες
[JavaScript Promises](https://youtu.be/oa2clhsYIDY) του David M. Lee (Nodevember 2014) ΕΝΗΜΕΡΩΣΗ (2016)
Υπάρχει μια νέα σύνταξη στο ECMA-262, 6th Edition, Section 14.2 που ονομάζεται arrow functions και μπορεί να χρησιμοποιηθεί για την περαιτέρω απλοποίηση των παραπάνω παραδειγμάτων. Χρησιμοποιώντας το API της jQuery, αντί για:
μπορείτε να γράψετε:
ή χρησιμοποιώντας το API Promises/A+:
Θυμηθείτε να χρησιμοποιείτε πάντα χειριστές απόρριψης είτε με:
είτε με:
Δείτε αυτή την απάντηση για να δείτε γιατί πρέπει πάντα να χρησιμοποιείτε χειριστές απόρριψης με υποσχέσεις:
promise.then(alert)
επειδή απλά καλείτε τοalert
με τα ίδια ορίσματα με το callback σας, αλλά η σύνταξη με το βέλος είναι πιο γενική και σας επιτρέπει να γράψετε πράγματα όπως:Δεν υποστηρίζουν ακόμα όλα τα προγράμματα περιήγησης αυτή τη σύνταξη, αλλά υπάρχουν ορισμένες περιπτώσεις όπου είστε σίγουροι σε ποιο πρόγραμμα περιήγησης θα τρέξει ο κώδικάς σας - π.χ. όταν γράφετε μια επέκταση του Chrome, ένα πρόσθετο του Firefox, ή μια desktop εφαρμογή που χρησιμοποιεί Electron, NW.js ή AppJS (δείτε αυτή την απάντηση για λεπτομέρειες). Για την υποστήριξη των συναρτήσεων βέλους, βλ:
await
που αντί αυτού του κώδικα:σας επιτρέπει να γράψετε:
Μπορείτε να το χρησιμοποιήσετε μόνο μέσα σε μια συνάρτηση που έχει δημιουργηθεί με τη λέξη κλειδί
async
. Για περισσότερες πληροφορίες, βλ:async
καιawait
μπορείτε να χρησιμοποιήσετε το Babel:co
ή στις coroutines του Bluebird:http://bluebirdjs.com/docs/api/promise.coroutine.html Περισσότερες πληροφορίες
Μερικές άλλες ερωτήσεις σχετικά με τις υποσχέσεις για περισσότερες λεπτομέρειες:
Ο μόνος τρόπος για να επιστρέψετε τα δεδομένα από τη συνάρτηση θα ήταν να κάνετε μια σύγχρονη κλήση αντί για μια ασύγχρονη κλήση, αλλά αυτό θα πάγωνε το πρόγραμμα περιήγησης ενώ περιμένει την απάντηση.
Μπορείτε να περάσετε μια συνάρτηση επανάκλησης που χειρίζεται το αποτέλεσμα:
Καλέστε την ως εξής:
Δείτε το παράδειγμα των εγγράφων jquery: http://api.jquery.com/jQuery.ajax/ (περίπου τα 2/3 της σελίδας)
Μπορεί να ψάχνετε για τον ακόλουθο κώδικα:
Ίδια σελίδα... πιο κάτω.