Future/Promise — τι είναι, ασύγχρονοι υπολογισμοί και προγραμματισμός

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-03-17 Χρόνος ανάγνωσης: 9 λεπ

Το Future/Promise είναι ένα μοτίβο ασύγχρονου προγραμματισμού που αντιπροσωπεύει ένα δοχείο για το αποτέλεσμα μιας λειτουργίας που δεν έχει ακόμη ολοκληρωθεί. Σύμφωνα με το Dart Documentation, 2025, το Future είναι το read-only αποτέλεσμα αναβληθέντων υπολογισμών, το Promise είναι ένα write-only συμβόλαιο που συμπληρώνει αυτό το αποτέλεσμα. Το Future χρησιμοποιείται σε Dart, Java, Scala και C++ για αλυσίδες then/catch.

Βασικά Σημεία

  • Future — read-only δοχείο για ασύγχρονο αποτέλεσμα διαθέσιμο στο μέλλον
  • Promise — write-only συμπληρωτής που λαμβάνει το αποτέλεσμα και το μεταδίδει στο Future
  • Αλυσίδες then — σειριακή επεξεργασία ασύγχρονων λειτουργιών χωρίς ένθετα callback
  • Future στη Dart — βάση των async/await και βιβλιοθηκών dio, http, shelf
  • Future/Promise — εναλλακτική στο μοτίβο callback και βάση της σύνταξης async/await

Τι είναι το Future/Promise;

Future/Promise είναι ένα ζεύγος αλληλένδετων αντικειμένων που διαχωρίζουν το ασύγχρονο αποτέλεσμα σε δύο ρόλους. Το Promise μπορεί να γράψει το αποτέλεσμα (resolve) ή το σφάλμα (reject). Το Future μπορεί μόνο να το διαβάσει — μέσω callback (then, catchError) ή μέσω await. Αυτός ο διαχωρισμός εγγυάται ότι ο καταναλωτής δεν μπορεί να αλλάξει το αποτέλεσμα, μόνο να το χρησιμοποιήσει.

Future στη Dart

Η γλώσσα Dart χρησιμοποιεί το Future ως κύριο μηχανισμό ασύγχρονου προγραμματισμού. Το Future<T> είναι ένα συμβόλαιο για τη λήψη μιας τιμής τύπου T στο μέλλον. Το Future μπορεί να βρίσκεται σε μία από τρεις καταστάσεις: unresolved (η λειτουργία εκτελείται), resolved with value (ολοκληρώθηκε επιτυχώς) ή resolved with error (ολοκληρώθηκε με σφάλμα). Μετά τη μετάβαση στην κατάσταση resolved, το Future δεν αλλάζει.

Promise στη JavaScript

Promise στη JavaScript είναι το ανάλογο του Future της Dart, αλλά με πλουσιότερο API. Το Promise δέχεται έναν executor — μια συνάρτηση με παραμέτρους resolve και reject. Οι στατικές μέθοδοι Promise.all, Promise.race, Promise.allSettled επιτρέπουν το συνδυασμό πολλών promise. Οι σύγχρονες εφαρμογές χρησιμοποιούν σύνταξη async/await πάνω από το Promise.

Πώς λειτουργεί το Future

Future λειτουργεί βάσει του event loop — του βρόχου γεγονότων που επεξεργάζεται ασύγχρονες λειτουργίες χωρίς να μπλοκάρει το κύριο νήμα. Όταν καλείται μια ασύγχρονη συνάρτηση (π.χ. http.get), επιστρέφει αμέσως ένα Future. Το πραγματικό αίτημα εκτελείται στο παρασκήνιο, ενώ ο event loop συνεχίζει να επεξεργάζεται άλλα γεγονότα. Μετά την ολοκλήρωση της λειτουργίας, το Future μεταβαίνει στην κατάσταση resolved και καλείται το then.

Event loop είναι ο βασικός μηχανισμός πάνω στον οποίο είναι χτισμένα τα Dart και JavaScript. Ο event loop διατηρεί δύο ουρές: microtask queue (σύντομες εργασίες που εκτελούνται πριν από το επόμενο γεγονός) και event queue (γεγονότα IO, χρονοδιακόπτες). Το Future.then τοποθετεί το callback στην microtask queue, το Future.microtask — εκτέλεση προτεραιότητας πριν από το επόμενο καρέ.

Οι αλυσίδες then() επιτρέπουν τη σειριακή επεξεργασία αποτελεσμάτων ασύγχρονων λειτουργιών χωρίς callback hell. Κάθε then() λαμβάνει το αποτέλεσμα του προηγούμενου βήματος και επιστρέφει ένα νέο Future. Το catchError() στο τέλος της αλυσίδας επεξεργάζεται οποιοδήποτε σφάλμα προέκυψε σε οποιοδήποτε βήμα. Αυτό κάνει τον ασύγχρονο κώδικα γραμμικό και ευανάγνωστο.

CompletableFuture στη Java

Στη Java, το CompletableFuture επεκτείνει την έννοια Future/Promise. Η μέθοδος supplyAsync() εκκινεί μια ασύγχρονη εργασία στο ForkJoinPool.commonPool(). Το thenApply() μετασχηματίζει το αποτέλεσμα, το thenCompose() — ξεδιπλώνει ένα ένθετο CompletableFuture. Το exceptionally() επεξεργάζεται το σφάλμα επιστρέφοντας μια προεπιλεγμένη τιμή. Τα allOf() και anyOf() λειτουργούν όπως τα Promise.all και Promise.race στη JavaScript. Το CompletableFuture υποστηρίζει χειροκίνητη ολοκλήρωση μέσω complete() και completeExceptionally() — αυτό είναι το ανάλογο του Promise resolve/reject.

Promise και ασύγχρονο συμβόλαιο

Promise είναι ένα συμβόλαιο με μία από τρεις καταστάσεις: pending (αναμονή), fulfilled (ολοκληρώθηκε επιτυχώς) ή rejected (ολοκληρώθηκε με σφάλμα). Μετά τη μετάβαση σε κατάσταση fulfilled ή rejected, το Promise δεν αλλάζει ποτέ — αυτό εγγυάται την αμεταβλητότητα του αποτελέσματος για όλους τους καταναλωτές. Η μέθοδος .then() καλείται ασύγχρονα μετά τη μετάβαση σε οποιαδήποτε ολοκληρωμένη κατάσταση.

Promise.all περιμένει την ολοκλήρωση όλων των παρεχόμενων promise και επιστρέφει έναν πίνακα αποτελεσμάτων με την ίδια σειρά. Αν ένα promise ολοκληρώθηκε με σφάλμα — ολόκληρο το Promise.all μεταβαίνει σε rejected. Το Promise.race επιστρέφει το αποτέλεσμα του πρώτου promise που ολοκληρώθηκε (επιτυχία ή σφάλμα). Το Promise.allSettled περιμένει όλα τα promise ανεξάρτητα από σφάλματα — επιστρέφει την κατάσταση του καθενός.

Chaining — το βασικό πλεονέκτημα του Promise έναντι του callback. Κάθε .then() επιστρέφει ένα νέο Promise, επιτρέποντας τη δημιουργία αλυσίδων αυθαίρετου μήκους. Ένα σφάλμα σε οποιονδήποτε κρίκο της αλυσίδας διαδίδεται μέχρι το πλησιέστερο .catch(). Η μέθοδος finally() εκτελεί κώδικα μετά την ολοκλήρωση της αλυσίδας ανεξάρτητα από το αποτέλεσμα — για καθαρισμό πόρων.

Παραδείγματα κώδικα Future (Dart)

Πρώτο παράδειγμα — δημιουργία Future μέσω async-συνάρτησης και επεξεργασία μέσω then/catchError:

dart
Future<String> fetchData() async {
    await Future.delayed(Duration(seconds: 1))
    return "Τα δεδομένα φορτώθηκαν"
}

fetchData()
    .then((result) => print(result))
    .catchError((error) => print("Σφάλμα: $error"))

Δεύτερο παράδειγμα — συνδυασμός πολλών Future μέσω Future.wait:

dart
Future<List<String>> loadAll() async {
    final futures = [
        fetchFromApi("/users"),
        fetchFromApi("/posts"),
        fetchFromApi("/comments")
    ]
    final results = await Future.wait(futures)
    return results
}

Τρίτο παράδειγμα — Promise στη JavaScript με χειροκίνητη δημιουργία και αλυσίδα then:

js
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("Έτοιμο")
    }, 1000)
})

promise
    .then(value => console.log(value))
    .catch(err => console.error(err))

Future vs άλλα ασύγχρονα μοτίβα

Future/Promise διαφέρει από το στυλ callback επειδή επιστρέφει ένα αντικείμενο-συμβόλαιο αντί να δέχεται μια συνάρτηση callback ως όρισμα. Το στυλ callback οδηγεί σε ένθεση (callback hell), ενώ το Future επιτρέπει τη δημιουργία επίπεδων αλυσίδων then(). Η σύνταξη async/await κάνει τον κώδικα με Future ακόμη πιο γραμμικό, παρόμοιο με σύγχρονο κώδικα.

Future αντιπροσωπεύει ακριβώς ένα ασύγχρονο αποτέλεσμα — μία εκπομπή, μετά την οποία το Future τελειώνει. Σε αντίθεση με το Observable (Rx, ReactiveX) ή το Flow (Kotlin Coroutines), το Future δεν υποστηρίζει πολλαπλές τιμές στο χρόνο. Αν χρειάζεστε μια ροή γεγονότων — χρησιμοποιήστε Stream στη Dart, Observable στο Rx ή Flow στο Kotlin.

CompletableFuture στη Java — το ανάλογο του Promise με εκτεταμένο API: supplyAsync, thenApply, thenCompose, exceptionally. Το CompletableFuture επιτρέπει το συνδυασμό πολλών ασύγχρονων λειτουργιών μέσω allOf, anyOf, καθώς και τον ορισμό δικού σας Executor για εκτέλεση. Το Scala Future χρησιμοποιεί ExecutionContext για τη διαχείριση του pool νημάτων και υποστηρίζει σύνθεση μέσω for-comprehension.

Στη Dart, το μοτίβο Future διαφέρει από το Promise της JavaScript επειδή η Dart έχει αυστηρή τυποποίηση: Future<String> εγγυάται τον τύπο της επιστρεφόμενης τιμής. Οι async συναρτήσεις στη Dart πρέπει να επιστρέφουν Future και ο μεταγλωττιστής ελέγχει αν όλα τα μονοπάτια επιστρέφουν τον σωστό τύπο. Το Future.wait είναι το ισοδύναμο του Promise.all — δέχεται Iterable<Future<T>> και επιστρέφει Future<List<T>>. Τα Future.delayed και Future.error είναι βολικές εργοστασιακές μέθοδοι για δοκιμή ασύγχρονων σεναρίων.

Το Future/Promise υλοποιείται στην Python μέσω των concurrent.futures.Future και asyncio.Future. Το concurrent.futures.ThreadPoolExecutor.submit() επιστρέφει ένα Future στο οποίο μπορεί να κληθεί result() — μια μπλοκάροντας κλήση. Το asyncio.Future είναι ένα δοχείο συμβατό με await για ασύγχρονο αποτέλεσμα στο Asyncio. Το asyncio.gather() εκτελεί πολλές κορουτίνες παράλληλα και επιστρέφει μια λίστα αποτελεσμάτων, παρόμοια με το Promise.all στη JavaScript. Η Python χρησιμοποιεί επίσης callback-based asyncio.ensure_future και αλυσίδες add_done_callback για σύνθεση ασύγχρονων λειτουργιών, αλλά στον σύγχρονο κώδικα προτιμάται η σύνταξη async/await με asyncio.Task.

Στην ανάπτυξη κινητών, το Future χρησιμοποιείται ενεργά σε εφαρμογές Flutter. Κάθε αίτημα δικτύου από το πακέτο http ή dio επιστρέφει Future. Το FutureBuilder — ένα widget που δέχεται ένα Future και ένα snapshot κατάστασης: connectionDone, hasData, hasError. Κατά τη λήψη δεδομένων, το snapshot.data περιέχει το αποτέλεσμα του Future. Το StreamBuilder — το ανάλογο για πολλαπλές τιμές. Το FutureBuilder εξαλείφει τη χειροκίνητη διαχείριση της κατάστασης φόρτωσης μέσω setState.

Το Scala Future χρησιμοποιεί σιωπηρά ExecutionContext — το pool νημάτων στο οποίο εκτελείται η ασύγχρονη εργασία. Η σύνθεση μέσω map, flatMap, filter λειτουργεί επειδή το Future είναι μονάδα. Το for-comprehension επιτρέπει το σειριακό συνδυασμό πολλών Future χωρίς ένθεση: for { a <- futureA; b <- futureB } yield a + b. Το Future.sequence λειτουργεί όπως το Promise.all. Η επαναφορά σε σφάλμα υλοποιείται μέσω recover και recoverWith.

Future/Promise στη C++ αντιπροσωπεύεται από τις κλάσεις std::future και std::promise από τη βιβλιοθήκη <future>. Το std::async εκκινεί μια ασύγχρονη συνάρτηση και επιστρέφει std::future. Το std::promise επιτρέπει τη χειροκίνητη ρύθμιση τιμής μέσω set_value() ή σφάλματος μέσω set_exception(). Σε αντίθεση με τη Dart και τη JavaScript, το std::future.get() μπλοκάρει το νήμα μέχρι τη λήψη του αποτελέσματος — αυτή είναι μια σημαντική διαφορά που πρέπει να ληφθεί υπόψη κατά το σχεδιασμό πολυνηματικών εφαρμογών στη C++.

Μοτίβα εργασίας με Future

Κατά το σχεδιασμό API που επιστρέφουν Future, ακολουθήστε τον κανόνα της μοναδικής πηγής αλήθειας: κάθε ασύγχρονο αίτημα δημιουργείται μία φορά και αποθηκεύεται στην κρυφή μνήμη μέσω Future.memoize. Αν δύο στοιχεία ζητούν τα ίδια δεδομένα, λαμβάνουν το ίδιο Future — αυτό αποτρέπει την επανάληψη αιτημάτων. Για timeout, χρησιμοποιήστε Future.timeout (Dart) ή Promise.race με timeout για να εγγυηθείτε ότι η ασύγχρονη λειτουργία θα ολοκληρωθεί εντός του καθορισμένου διαστήματος.

Μοτίβο Retry στο Future υλοποιείται μέσω αναδρομικής αλυσίδας: σε σφάλμα στο catch, η ίδια ασύγχρονη συνάρτηση καλείται με καθυστέρηση. Το Exponential backoff αυξάνει το διάστημα μεταξύ προσπαθειών: 1 δευτ — 2 δευτ — 4 δευτ — έως μέγ 30 δευτ. Στη Dart, αυτό ενσωματώνεται σε ένα extension στο Future: future.retry(maxRetries: 3, delay: Duration(seconds: 1)). Στη Scala, το Future.zip συνδυάζει δύο ανεξάρτητα αποτελέσματα σε ένα tuple — εναλλακτική στο Promise.all για δύο Future. Η ακύρωση (Cancellation) δεν υποστηρίζεται σε τυπικά Future, αλλά υλοποιείται μέσω CancellationToken ή AbortController στη JavaScript.

Συχνές Ερωτήσεις

Ποια είναι η διαφορά μεταξύ Future και Promise;

Future είναι ένα read-only δοχείο για ανάγνωση ασύγχρονου αποτελέσματος μέσω then ή await. Το Promise είναι ένα write-only συμβόλαιο που λαμβάνει τιμή μέσω resolve() και τη συνδέει με το Future. Στη Dart και τη JavaScript, αυτές οι έννοιες είναι ενοποιημένες: Future/Promise είναι μία κλάση. Στη Java και τη Scala είναι ξεχωριστές.

Σε τι διαφέρει το Future από το Observable;

Future αντιπροσωπεύει ένα μοναδικό ασύγχρονο αποτέλεσμα — εκπέμπει ακριβώς μία τιμή και τελειώνει. Το Observable (Rx) εκπέμπει πολλαπλές τιμές στο χρόνο — αυτή είναι μια ασύγχρονη ροή. Αν χρειάζεστε μία απόκριση HTTP — χρησιμοποιήστε Future. Αν χρειάζεστε μια ροή αλλαγών βάσης δεδομένων — χρησιμοποιήστε Observable ή Stream.

Τι είναι το async/await και πώς σχετίζεται με το Future;

async/await είναι συντακτική ζάχαρη πάνω από το Future/Promise. Η λέξη-κλειδί async σημαδεύει μια συνάρτηση ως ασύγχρονη — επιστρέφει Future. Το await αναστέλλει την εκτέλεση μέχρι την ολοκλήρωση του Future, χωρίς να μπλοκάρει το νήμα. Σε Dart, JavaScript, Python και C#, το async/await έχει αντικαταστήσει τις αλυσίδες then στα περισσότερα σενάρια.

Πώς να χειρίζεστε σφάλματα σε μια αλυσίδα Future;

Στη Dart, χρησιμοποιήστε .catchError() στο τέλος της αλυσίδας — πιάνει εξαιρέσεις σε οποιοδήποτε στάδιο. Στη JavaScript — .catch(). Στη Dart, το try/await/catch είναι επίσης διαθέσιμο μέσα σε συναρτήσεις async. Για ανάκτηση μετά από σφάλμα, χρησιμοποιήστε .catchError() με επιστροφή προεπιλεγμένης τιμής ή νέου Future.

Τι είναι το Promise.all και πότε να το χρησιμοποιείτε;

Promise.all δέχεται έναν πίνακα promise και επιστρέφει ένα Promise που επιλύεται με έναν πίνακα αποτελεσμάτων. Όλα τα promise εκκινούνται παράλληλα — αυτό επιταχύνει την εκτέλεση ανεξάρτητων λειτουργιών (π.χ. φόρτωση πολλών αρχείων). Αν οποιοδήποτε promise απορριφθεί — ολόκληρο το Promise.all απορρίπτεται με το ίδιο σφάλμα.

Σύνοψη

  • Future/Promise — μοτίβο ασύγχρονου προγραμματισμού με συμβόλαιο για μία τιμή
  • Future — read-only δοχείο για ανάγνωση του αποτελέσματος λειτουργίας
  • Promise — write-only συμβόλαιο που συμπληρώνει το Future μέσω resolve/reject
  • Αλυσίδες then — επίπεδη επεξεργασία ασύγχρονων βημάτων χωρίς callback hell
  • async/await — συντακτική ζάχαρη πάνω από Future, κάνει τον κώδικα γραμμικό
  • Promise.all — παράλληλη εκτέλεση πολλαπλών ασύγχρονων λειτουργιών
  • Για πολλαπλές τιμές στο χρόνο, χρησιμοποιήστε Stream ή Observable, όχι Future

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης