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-ја асинхрони код се градио на callback-овима, GCD-ју или RxSwift-у. Ланци угњеждених callback-ова доводили су до 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, она се суспендује, ослобађајући тренутну нит за друге задатке. Након завршетка асинхроне операције функција се наставља на истој или другој нити. Ово се назива кооперативна мултитаскинг.
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-а преко serial редова и DispatchGroup-а, али остаје опширан. За једноставан задатак — учитати user, затим friends, затим UI — потребно је креирање редова, група и notify блокова. Async/Await обавља исти задатак са три линије у једној функцији.
| Аспект | Callback | GCD | Async/Await |
|---|---|---|---|
| Угњежђивање | Дубоко (pyramid of doom) | Средње (групе+notify) | Линеарно (flat) |
| Обрада грешака | Per-callback | Ручна | Јединствена (try/catch) |
| Отказивање | Ручно | Ограничено | Task.cancel() |
| Thread safety | Ручно | Преко serial queue | Преко MainActor-а |
Према подацима Apple WWDC 2024, Swift Concurrency async/await — препоручени приступ за нови код. GCD остаје за интеграцију са C библиотекама и специфичне low-level сценаријe обраде нити.
Task — основна јединица асинхроног рада у Swift-у. Task се креира у контексту постојећег актора или на произвољној нити. Унутар Task-а могу се позивати async функције преко await. TaskGroup омогућава покретање неколико дочерњих задатака паралелно и прикупљање њихових резултата — аналог DispatchGroup-а на стероидима.
Actor — thread-safe reference тип, који штити своје стање од трка података (data races). Компајлер гарантује да је приступ својствима актора могућ само преко async позива или у оквиру actor isolation-а. Actor замењује serial DispatchQueue за заштиту shared mutable стања без ручних закључавања.
Принцип Structured Concurrency гласи: свака асинхрона задатка има родитеља, и родитељ се не завршава док се не заврше сва његова деца. Ако задатак A покрене Task { await B() }, онда A чека B. Ово спречава цурење задатака и обезбеђује предвидив lifecycle.
У Kotlin-у async/await је реализован преко coroutines — лаганих нити језика. Функција се означава кључном речју suspend (аналог Swift-овог 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 суспендује извршавање док се не добију подаци корисника, затим — док се не добију пријатељи. Без угњеждених затворења.
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 на нивоу оперативног система.
Не — await суспендује функцију, али ослобађа нит за друге задатке. Након завршетка операције функција се наставља на било којој доступној нити из пула.
Да — преко Task.cancel() у Swift-у или Job.cancel() у Kotlin-у. Отказивање се проширује на све дочерње задатке према Structured Concurrency. Код сам проверава флаг отказивања преко Task.isCancelled или ensureActive().
MainActor — актор чија се својства и методе увек извршавају на главној нити. Обележавајући функцију @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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође