Async/Await — είναι ένα ζεύγος λέξεων-κλειδιών για τη σύνταξη ασύγχρονου κώδικα σε σύγχρονο στυλ, διαθέσιμο σε Swift από το iOS 13 και σε Kotlin με κορουτίνες. Σύμφωνα με το Apple Swift Documentation, 2026, το Async/Await αντικαθιστά αλυσίδες callback και GCD, κάνοντας τον ασύγχρονο κώδικα γραμμικό και ευανάγνωστο. Η λέξη-κλειδί async χαρακτηρίζει μια συνάρτηση ως ασύγχρονη, ενώ το await αναστέλλει την εκτέλεσή της μέχρι τη λήψη του αποτελέσματος.
Βασικά σημεία
Async/Await — είναι μια γλωσσική κατασκευή που επιτρέπει τη σύνταξη ασύγχρονου κώδικα με τον ίδιο γραμμικό τρόπο όπως ο σύγχρονος. Σε Swift εμφανίστηκε στο iOS 13 / macOS 10.15 μαζί με το πλαίσιο Swift Concurrency. Σε Kotlin το async/await είναι διαθέσιμο μέσω της βιβλιοθήκης κορουτινών (kotlinx.coroutines) από την έκδοση 1.3.
Πριν από την εμφάνιση του async/await, ο ασύγχρονος κώδικας βασιζόταν σε callbacks, GCD ή RxSwift. Οι αλυσίδες εμφωλευμένων callbacks οδηγούσαν σε callback hell — βαθιά εμφώλευση που περιπλέκει την ανάγνωση και τον εντοπισμό σφαλμάτων. Το Async/Await λύνει αυτό το πρόβλημα επιτρέποντας στις ασύγχρονες συναρτήσεις να “αναστέλλονται” στα σημεία await και να συνεχίζουν μετά τη λήψη του αποτελέσματος.
Σύμφωνα με δεδομένα Google (2025), η χρήση async/await σε Kotlin μειώνει τον αριθμό γραμμών ασύγχρονου κώδικα κατά 40–60% σε σύγκριση με την προσέγγιση callback. Σε Swift, η υιοθέτηση Swift Concurrency έφτασε το 68% μεταξύ των δημοσιευμένων εφαρμογών το 2025. iOS 16 πρόσθεσε υποστήριξη Swift Concurrency σε UIKit, SwiftUI και Foundation, καθιστώντας το async/await βασικό εργαλείο για όλα τα νέα έργα Apple.
Η βασική διαφορά του async/await από τα νήματα — αναστολή χωρίς αποκλεισμό. Όταν μια συνάρτηση συναντά await, αναστέλλεται, ελευθερώνοντας το τρέχον νήμα για άλλες εργασίες. Μετά την ολοκλήρωση της ασύγχρονης λειτουργίας, η συνάρτηση συνεχίζει στο ίδιο ή σε άλλο νήμα. Αυτό ονομάζεται cooperative multitasking.
Η async συνάρτηση μεταγλωττίζεται σε state machine — ένα πεπερασμένο αυτόματο που διαχειρίζεται καταστάσεις εκτέλεσης. Στο σημείο await, ο μεταγλωττιστής αποθηκεύει το περιβάλλον (τοπικές μεταβλητές, διεύθυνση επιστροφής) και παραδίδει τον έλεγχο στο runtime. Όταν το αποτέλεσμα είναι έτοιμο, το runtime επαναφέρει το περιβάλλον και συνεχίζει την εκτέλεση.
Σε Swift αυτή η state machine υλοποιείται σε επίπεδο μεταγλωττιστή SIL (Swift Intermediate Language). Σε Kotlin — μέσω του μηχανισμού Continuation Passing Style (CPS): κάθε suspend συνάρτηση δέχεται μια κρυφή παράμετρο Continuation, μέσω της οποίας επιστρέφεται το αποτέλεσμα. Και οι δύο προσεγγίσεις εγγυώνται ασφαλή επανάληψη χωρίς διαρροές μνήμης.
Η προσέγγιση callback απαιτεί τη μεταβίβαση ενός closure, το οποίο καλείται μετά την ολοκλήρωση της λειτουργίας. Με τρία διαδοχικά αιτήματα προκύπτουν τρία επίπεδα εμφώλευσης με χειρισμό σφαλμάτων σε κάθε ένα. Async/Await μετατρέπει τα ίδια τρία αιτήματα σε τρεις διαδοχικές γραμμές με ενιαίο μπλοκ catch.
GCD (DispatchQueue) λύνει το πρόβλημα callback hell μέσω σειριακών ουρών και DispatchGroup, αλλά παραμένει πολυλογικό. Για μια απλή εργασία — φόρτωση user, στη συνέχεια friends, στη συνέχεια UI — απαιτείται δημιουργία ουρών, ομάδων και μπλοκ notify. Async/Await εκτελεί την ίδια εργασία με τρεις γραμμές σε μία συνάρτηση.
| Πτυχή | Callback | GCD | Async/Await |
|---|---|---|---|
| Εμφώλευση | Βαθιά (pyramid of doom) | Μεσαία (ομάδες+notify) | Γραμμική (flat) |
| Χειρισμός σφαλμάτων | Ανά callback | Χειροκίνητος | Ενιαίος (try/catch) |
| Ακύρωση | Χειροκίνητη | Περιορισμένη | Task.cancel() |
| Thread safety | Χειροκίνητη | Μέσω σειριακής ουράς | Μέσω MainActor |
Σύμφωνα με δεδομένα Apple WWDC 2024, το Swift Concurrency async/await είναι η συνιστώμενη προσέγγιση για νέο κώδικα. Το GCD παραμένει για ενσωμάτωση με βιβλιοθήκες C και συγκεκριμένα σενάρια χαμηλού επιπέδου επεξεργασίας νημάτων.
Task — είναι η βασική μονάδα ασύγχρονης εργασίας σε Swift. Το Task δημιουργείται στο περιβάλλον ενός υπάρχοντος actor ή σε οποιοδήποτε νήμα. Μέσα στο Task μπορούν να κληθούν async συναρτήσεις μέσω await. TaskGroup επιτρέπει την παράλληλη εκτέλεση πολλαπλών θυγατρικών εργασιών και τη συλλογή των αποτελεσμάτων τους — ανάλογο του DispatchGroup στα στεροειδή.
Actor — είναι ένας νηματασφαλής reference type που προστατεύει την κατάστασή του από συνθήκες ανταγωνισμού δεδομένων. Ο μεταγλωττιστής εγγυάται ότι η πρόσβαση στις ιδιότητες του actor είναι δυνατή μόνο μέσω async κλήσεων ή εντός actor isolation. Actor αντικαθιστά τη σειριακή DispatchQueue για προστασία κοινής μεταβλητής κατάστασης χωρίς χειροκίνητα κλειδώματα.
Η αρχή Structured Concurrency ορίζει: κάθε ασύγχρονη εργασία έχει έναν γονέα και ο γονέας δεν ολοκληρώνεται έως ότου ολοκληρωθούν όλα τα παιδιά του. Αν η εργασία A εκκινήσει Task { await B() }, τότε το A αναμένει το B. Αυτό αποτρέπει διαρροές εργασιών και εξασφαλίζει προβλέψιμο κύκλο ζωής.
Σε Kotlin το async/await υλοποιείται μέσω coroutines — ελαφρών νημάτων της γλώσσας. Η συνάρτηση χαρακτηρίζεται με τη λέξη-κλειδί suspend (ανάλογο του Swift’s async). Για εκκίνηση χρησιμοποιείται launch (fire-and-forget) ή async (με αποτέλεσμα). Το Await καλείται για τη λήψη του αποτελέσματος από async.
Dispatcher καθορίζει σε ποιο σύνολο νημάτων εκτελείται η κορουτίνα: Dispatchers.Main για UI, Dispatchers.IO για δίκτυο/δίσκο και Dispatchers.Default για εργασίες έντασης CPU. Structured Concurrency εξασφαλίζεται μέσω CoroutineScope — κατά την ακύρωση του scope ακυρώνονται όλες οι θυγατρικές κορουτίνες.
Σύμφωνα με δεδομένα JetBrains (2025), το 97% των Android εφαρμογών στο Google Play χρησιμοποιούν kotlinx.coroutines και το 82% από αυτές εφαρμόζουν async/await για δικτυακά αιτήματα. Οι coroutines έχουν γίνει de facto πρότυπο για ασύγχρονο προγραμματισμό σε Android. Kotlin Multiplatform υποστηρίζει επίσης κορουτίνες, επιτρέποντας τη χρήση κοινού ασύγχρονου κώδικα σε Android, iOS και διακομιστή.
Ας δούμε δύο παραδείγματα για κάθε γλώσσα: σειριακή φόρτωση δεδομένων και παράλληλα αιτήματα με TaskGroup ή async/await.
await αναστέλλει την εκτέλεση μέχρι τη λήψη δεδομένων χρήστη, στη συνέχεια — μέχρι τη λήψη φίλων. Καθόλου εμφωλευμένα closures.
func loadProfile() async throws -> Profile {
let user = try await api.fetchUser()
let friends = try await api.fetchFriends(for: user.id)
return Profile(user: user, friends: friends)
}
TaskGroup εκτελεί εργασίες παράλληλα και συλλέγει τα αποτελέσματα σε πίνακα. Η σειρά των αποτελεσμάτων μπορεί να μην συμπίπτει με τη σειρά εκκίνησης.
func loadParallel() async throws -> [String] {
await withThrowingTaskGroup(of: String.self) { group in
group.addTask { try await api.fetchName() }
group.addTask { try await api.fetchEmail() }
group.addTask { try await api.fetchAvatar() }
var results = [String]()
for try await value in group { results.append(value) }
return results
}
}
Οι suspend συναρτήσεις μπορούν να καλούν άλλες suspend συναρτήσεις. Ανάλογο Swift: σειριακές κλήσεις.
suspend fun loadProfile(): Profile {
val user = api.fetchUser()
val friends = api.fetchFriends(user.id)
return Profile(user, friends)
}
Σε Kotlin ο παραλληλισμός επιτυγχάνεται μέσω coroutineScope με async για κάθε αίτημα.
suspend fun loadParallel(): List<String> = coroutineScope {
val name = async { api.fetchName() }
val email = async { api.fetchEmail() }
val avatar = async { api.fetchAvatar() }
listOf(name.await(), email.await(), avatar.await())
}
Ξεχασμένο Task { } — μια ασύγχρονη συνάρτηση δεν μπορεί να κληθεί από σύγχρονο περιβάλλον χωρίς περιτύλιγμα σε Task. Σε Swift αυτό προκαλεί σφάλμα μεταγλώττισης. Σε Kotlin απαιτείται εκκίνηση μέσω lifecycleScope ή viewModelScope. Η προσπάθεια κλήσης suspend συνάρτησης από κανονική συνάρτηση δεν θα μεταγλωττιστεί.
Δεν χρειάζεται να γίνει κάθε συνάρτηση ασύγχρονη. Εργασίες έντασης CPU χωρίς I/O δεν επωφελούνται από async — είναι καλύτερο να εκτελούνται σε DispatchQueue με .userInitiated QoS. Το Async/Await είναι βελτιστοποιημένο για λειτουργίες I/O-bound: δίκτυο, δίσκος, αναμονή.
Η χρήση .result στο κύριο νήμα (σύγχρονη αναμονή αποτελέσματος async συνάρτησης) οδηγεί σε αποκλεισμό. Σε Swift το Task.synchronousWait δεν συνιστάται από την Apple. Σε Kotlin το runBlocking στο κύριο νήμα είναι αντιπρότυπο, χρησιμοποιήστε lifecycleScope.
Αν το Task δεν αποθηκευτεί σε ιδιότητα κλάσης, μετά την έξοδο από το περιβάλλον ακυρώνεται. Σε Swift το Task είναι scoped — ο κύκλος ζωής του είναι συνδεδεμένος με το δημιουργό περιβάλλον. Αποθηκεύστε το Task σε ιδιότητα όταν χρειάζεστε μακροχρόνια λειτουργία.
Συχνές ερωτήσεις
Async/Await — γλωσσική κατασκευή που δεν απαιτεί δημιουργία ουρών. DispatchQueue — είναι ένα σύστημα API για διαχείριση νημάτων. Το async/await μεταγλωττίζεται σε state machine σε επίπεδο γλώσσας, το GCD — σε syscall σε επίπεδο OS.
Όχι — το await αναστέλλει τη συνάρτηση, αλλά ελευθερώνει το νήμα για άλλες εργασίες. Μετά την ολοκλήρωση της λειτουργίας, η συνάρτηση συνεχίζεται σε οποιοδήποτε διαθέσιμο νήμα από τη δεξαμενή.
Ναι — μέσω Task.cancel() σε Swift ή Job.cancel() σε Kotlin. Η ακύρωση διαδίδεται σε όλες τις θυγατρικές εργασίες σύμφωνα με το Structured Concurrency. Ο κώδικας ελέγχει την ένδειξη ακύρωσης μέσω Task.isCancelled ή ensureActive().
MainActor — είναι ένας actor του οποίου οι ιδιότητες και οι μέθοδοι εκτελούνται πάντα στο κύριο νήμα. Χαρακτηρίζοντας μια συνάρτηση με @MainActor, εγγυάστε ότι οι ενημερώσεις UI γίνονται στο σωστό νήμα, αντικαθιστώντας το DispatchQueue.main.async.
Το Async/Await είναι διαθέσιμο σε Swift (iOS 13+), Kotlin (μέσω kotlinx.coroutines), Dart (Flutter), JavaScript/TypeScript, Python, C#, Rust και Go (μέσω goroutines με συντακτική ζάχαρη).
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης