Promises
Όταν γράφουμε ασύγχρονο κώδικα στη JavaScript, μία μοντέρνα μεθόδος για να χειριστούμε αποτελέσματα που θα λάβουμε μελλοντικά (όπως απαντήσεις από έναν server), είναι μέσω της χρήσης των Promises. Τα Promises μας επιτρέπουν να οργανώνουμε αλυσιδωτές λειτουργίες και να διαχειριζόμαστε επιτυχίες και αποτυχίες σε ασύγχρονες διαδικασίες, αποφεύγοντας το γνωστό "Callback Hell" που αναφέραμε στην προηγούμενη ενότητα.
Δημιουργία ενός Promise
Ένα Promise δημιουργείται μέσω του constructor promise, ο οποίος δέχεται μια συνάρτηση με δύο παραμέτρους. Η συνάρτηση αυτή ονομάζεται executor (εκτελεστής) και εκτελείται αυτόματα μόλις δημιουργηθεί το Promise.
Τα δύο ορίσματα που δέχεται, resolve και reject, είναι callback functions και έχουν τις εξής λειτουργίες:
- resolve: Η διαδικασία επιτυγχάνει και μας επιστρέφεται η τελική τιμή.
- reject: Η διαδικασία αποτυγχάνει και μας επιστρέφεραι ένα error
object, δηλαδή το exception value.
const myPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve('Επιτυχία!');
} else {
reject('Αποτυχία');
}
});
Στο παραπάνω παράδειγμα, η arrow function είναι η συνάρτηση executor. Η παράμετρος resolve καλείται καθώς η διαδικασία που θέλουμε να εκτελέσουμε στην executor function επιτυγχάνει.
Κατάσταση ενός Promise
Ένα Promise έχει τρείς δυνατές καταστάσεις:
| Κατάσταση | Περιγραφή |
|---|---|
pending | Το promise δεν έχει ακόμη επιλυθεί |
fulfilled | Το promise επιλύθηκε με επιτυχία |
rejected | Το promise απορρίφθηκε λόγω σφάλματος |
Μόλις φύγει από την κατάσταση Pending, το Promise "κλειδώνει και δεν αλλάζει ξανά κατάσταση.
Μέθοδοι .then() και .catch()
Για να χειριστούμε το αποτέλεσμα ενός Promise, χρησιμοποιούμε τις μεθόδους .then() και .catch().
- H
thenκαλείται όταν το Promise επιλυθεί επιτυχώς. - Η
catchκαλείται όταν το Promise απορριφθεί λόγω σφάλματος.
let promise = new Promise((resolve, reject) => {
resolve("success");
});
myPromise
.then((message) => {
console.log("Μήνυμα": message);
})
.catch((error) => {
console.error("Σφάλμα": error);
});
- H
thenκαλείται όταν το Promise επιλυθεί επιτυχώς. - Η
catchκαλείται όταν το Promise απορριφθεί λόγω σφάλματος.
Αν καλέσεις .then() ή .catch() πάνω σε ένα Promise που έχει ήδη επιλυθεί ή απορριφθεί, ο χειριστής θα εκτελεστεί άμεσα, χωρίς καθυστέρηση. Τα Promises είναι μιας χρήσης που σημαίνει ότι δεν μπορούν να "επαναληφθούν" ή να "ξαναπροσπαθήσουν".
Αλυσιδωτές Λειτουργίες (Chaining)
Ένα από τα χαρακτηριστικά των Promises είναι η δυνατότητα να δημιουργόυμε αλυσίδες ενεργειών.
Για παράδειγμα:
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => response.json())
.then((data) => {
console.log("Δεδομένα:", data)
});
.catch((error) => {
cosole.error("Σφάλμα στο fetch:", error);
});
Κάθε .then() επιστρέφει ένα νέο Promise, επιτρέποντας συνεχή επεξεργασία δεδομένων.
Promise.all και Promise.race
Η Javascript παρέχει μερικές βοηθητικές στατικές μεθόδους για συνδιασμό πολλών Promises:
Promise.all
Εκτελεί πολλά Promises και περιμένει όλα να ολοκληρωθούν.
Για παράδειγμα:
const promise1 = Promise.resolve(5);
const promise2 = Promise.resolve(10);
Promise.all([promise1, promise2])
.then(([result1, result2]) => {
console.log('Αποτέλεσμα 1:', result1); // 5
console.log('Αποτέλεσμα 2:', result2); // 10
})
.catch(console.error);
Βλάπουμε οτι η σύνταξη του Promise.all δέχεται έναν πίνακα από Promises και επιστρέφει ένα νέο Promise που επιλύεται όταν όλα τα Promises στον πίνακα έχουν επιλυθεί.
Σε αυτό το παράδειγμα, έχουμε δύο απλά Promises που γίνονται άμεσα resolved. Το Promise.all περιμένει και τα δύο να ολοκληρωθούν και μετά δίνει τα αποτελέσματά τους σαν πίνακα.
Promise.race
Επιστρέφει το αποτέλεσμα του πρώτου Promise που θα ολοκληρωθεί.
Για παράδειγμα:
const fast = new Promise((res) => setTimeout(() => res('Γρήγορο'), 500));
const slow = new Promise((res) => setTimeout(() => res('Αργό'), 1000));
Promise.race([fast, slow]).then(console.log); // "Γρήγορο"
Η σύνταξη του Promise.race δέχεται έναν πίνακα από Promises και επιστρέφει ένα νέο Promise που επιλύεται ή απορρίπτεται μόλις ένα από τα Promises στον πίνακα ολοκληρωθεί.
Πλεονεκτήματα
- Καθαρός κώδικας από τα callbacks.
- Αποφυγή nested callbacks (callback hell).
- Εύκολος χειρισμός σφαλμάτων με
.catch(). - Συμβατότητα με
async/await, για καθαρότερο κώδικα.
Σύγκριση με άλλες προσεγγίσεις
| Προσέγγιση | Πλεονεκτήματα | Μειονεκτήματα |
|---|---|---|
Callbacks | Απλή και ευέλικτη | Δύσκολος έλεγχος ροής, callback hell |
Promises | Καλύτερη ροή, ευκολότερο debugging | Περίπλοκες αλυσίδες μπορεί να μπερδέψουν |
async/await | Συγχρονική μορφή, πιο καθαρός χειρισμός | Απαιτεί κατανόηση των Promises |
Στην επόμενη ενότητα, θα εξετάσουμε το async/await, που βασ ίζεται στα Promises και προσφέρει έναν ακόμη πιο καθαρό τρόπο διαχείρισης ασύγχρονου κώδικα.