Το πρόβλημα του promise hell στην JavaScript
Γνωρίζετε ήδη ότι οι υποσχέσεις (promises) δημιουργήθηκαν για να λύσουν το πρόβλημα του callback hell. Ωστόσο, με το πέρασμα του χρόνου, αποδείχθηκε ότι οι υποσχέσεις μπορούν επίσης να δημιουργήσουν πολύπλοκο κώδικα. Αυτό το πρόβλημα αναφέρθηκε αναλογικά ως promise hell.
Ας εξετάσουμε αυτό το πρόβλημα με παραδείγματα
κώδικα. Ας υποθέσουμε ότι έχουμε μια συνάρτηση getSmth,
που λαμβάνει μια παράμετρο και επιστρέφει ένα αποτέλεσμα
ανάλογα με αυτήν την παράμετρο:
function getSmth(num) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num * num), 1000)
});
}
Σε αυτήν την περίπτωση, προσομοιώνουμε μια χρήσιμη λειτουργία (για παράδειγμα, λήψη δεδομένων από έναν διακομιστή). Για την προσομοίωση, απλώς μεταβιβάζουμε έναν αριθμό ως παράμετρο και μετά από ένα δευτερόλεπτο επιστρέφουμε το τετράγωνο αυτού του αριθμού.
Ας χρησιμοποιήσουμε τώρα τη συνάρτησή μας
getSmth μέσα σε μια άλλη συνάρτηση:
function func() {
getSmth(2).then(res => {
console.log(res); // θα εμφανίσει 4
});
}
func();
Πρώτο πρόβλημα
Πολλές διαδοχικές δομές
then δυσκολεύουν την κατανόηση του κώδικα:
function func(){
getSmth(2).then(res1 => {
// κάνουμε κάτι
}).then(res2 => {
// κάνουμε κάτι
}).then(res3 => {
// κάνουμε κάτι
}).then(res4 => {
// κάνουμε κάτι
}).then(res5 => {
// κάνουμε κάτι
}).then(res6 => {
// κάνουμε κάτι
});
}
func();
Δεύτερο πρόβλημα
Υπάρχει ένα πρόβλημα και άλλου τύπου. Ας υποθέσουμε τώρα ότι θέλουμε να χρησιμοποιήσουμε τη συνάρτησή μας δύο φορές και στη συνέχεια να αθροίσουμε τα αποτελέσματα. Ως αποτέλεσμα θα έχουμε τον ακόλουθο κώδικα:
function func() {
getSmth(2).then(res1 => {
getSmth(3).then(res2 => {
console.log(res1 + res2); // θα εμφανίσει 13
});
});
}
func();
Θυμίζει ήδη callback hell, έτσι δεν είναι; Ας προσθέσουμε μια ακόμη κλήση συνάρτησης - ο κώδικας θα γίνει ακόμα χειρότερος:
function func() {
getSmth(2).then(res1 => {
getSmth(3).then(res2 => {
getSmth(4).then(res3 => {
console.log(res1 + res2 + res3);
});
});
});
}
func();
Μπορούμε, φυσικά, να χρησιμοποιήσουμε το Promise.all:
function func() {
Promise.all([getSmth(2), getSmth(3), getSmth(4)]).then(res => {
console.log(res[0] + res[1] + res[2]);
});
}
func();
Ωστόσο, πήραμε το ίδιο πράγμα; Όχι! Στην πρώτη περίπτωση, κάθε νέα συνάρτηση περιμένει να ολοκληρωθεί η προηγούμενη υπόσχεση, ενώ στη δεύτερη περίπτωση - όλες οι υποσχέσεις εκτελούνται ταυτόχρονα. Αυτή η διαφορά θα είναι σημαντική στην περίπτωση που θέλουμε να περάσουμε το αποτέλεσμα της προηγούμενης συνάρτησης στην επόμενη συνάρτηση:
function func() {
getSmth(2).then(res1 => {
getSmth(res1).then(res2 => {
getSmth(res2).then(res3 => {
console.log(res3);
});
});
});
}
func();