Async/Await: суштина, async функције и рад са await

Аутор: IT Sectr Објављено: 2026-03-16 Време читања: 8 мин

Async/Await — пар кључних речи за писање асинхроног кода у синхроном стилу, доступан у Swift-у од iOS 13 и у Kotlin-у са корутинама. Према Apple Swift Documentation, 2026, Async/Await замењује ланце callback-ова и GCD, чинећи асинхрони код линеарним и читљивим. Кључна реч async означава функцију као асинхрону, а await суспендује њено извршавање док се не добије резултат.

Главно

  • Async/Await — синтаксни шећер за асинхрони код без угњеждених callback-ова
  • async означава функцију као асинхрону и суспендује је
  • await суспендује извршавање функције док се не заврши асинхрона операција
  • Task у Swift-у ствара нову асинхрону јединицу рада са контекстом
  • Structured Concurrency гарантује да се све дочерње задатке завршавају пре родитељске

Шта је 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/Await: суспендовање и настављање

Async функција се компајлира у state machine — коначни аутомат који управља стањима извршавања. У тачки await компајлер чува контекст (локалне променљиве, адресу повратка) и предаје контролу runtime-у. Када је резултат спреман, runtime обнавља контекст и наставља извршавање.

У Swift-у је овај state machine реализован на нивоу компајлера SIL (Swift Intermediate Language). У Kotlin-у — преко механизма Continuation Passing Style (CPS): свака suspend функција прима скривени параметар Continuation, преко кога се враћа резултат. Оба приступа гарантују безбедно настављање без цурења меморије.

  • Swift — компајлер преводи async функцију у SIL са runAsync coroutine frame
  • Kotlin — свака suspend функција добија Continuation и делегира извршавање диспечеру
  • Оба језика — ослобађају нит при await, не блокирајући је током чекања
  • Изузеци — прослеђују се стандардним механизмима (throws / try-catch)

Async/Await против Callbacks-а и GCD-ја: поређење приступа

Callback приступ захтева прослеђивање затворења (closure) које се позива након завршетка операције. Код три узастопна захтева добијају се три нивоа угњежђивања са обрадом грешака на сваком. Async/Await претвара иста три захтева у три узастопне линије са јединственим catch блоком.

GCD (DispatchQueue) решава проблем callback hell-а преко serial редова и DispatchGroup-а, али остаје опширан. За једноставан задатак — учитати user, затим friends, затим UI — потребно је креирање редова, група и notify блокова. Async/Await обавља исти задатак са три линије у једној функцији.

АспектCallbackGCDAsync/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 обраде нити.

Swift Concurrency: Task, TaskGroup и Actor

Task — основна јединица асинхроног рада у Swift-у. Task се креира у контексту постојећег актора или на произвољној нити. Унутар Task-а могу се позивати async функције преко await. TaskGroup омогућава покретање неколико дочерњих задатака паралелно и прикупљање њихових резултата — аналог DispatchGroup-а на стероидима.

Actor — thread-safe reference тип, који штити своје стање од трка података (data races). Компајлер гарантује да је приступ својствима актора могућ само преко async позива или у оквиру actor isolation-а. Actor замењује serial DispatchQueue за заштиту shared mutable стања без ручних закључавања.

Structured Concurrency

Принцип Structured Concurrency гласи: свака асинхрона задатка има родитеља, и родитељ се не завршава док се не заврше сва његова деца. Ако задатак A покрене Task { await B() }, онда A чека B. Ово спречава цурење задатака и обезбеђује предвидив lifecycle.

Async/Await у Kotlin-у са корутинама

У 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-у и серверској страни.

Примери кода са Async/Await у Swift-у и Kotlin-у

Погледајмо по два примера за сваки језик: секвенцијално учитавање података и паралелни захтеви са TaskGroup или async/await.

Swift: секвенцијални async позиви

await суспендује извршавање док се не добију подаци корисника, затим — док се не добију пријатељи. Без угњеждених затворења.

swift
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)
}

Swift: паралелни захтеви са TaskGroup

TaskGroup покреће задатке паралелно и прикупља резултате у низ. Редослед резултата може да се не подудара са редоследом покретања.

swift
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
    }
}

Kotlin: секвенцијални позив са async/await

suspend функције могу да позивају друге suspend функције. Аналог Swift-у: секвенцијални позиви.

kotlin
suspend fun loadProfile(): Profile {
    val user = api.fetchUser()
    val friends = api.fetchFriends(user.id)
    return Profile(user, friends)
}

Kotlin: паралелни захтеви са async/await

У Kotlin-у паралелизам се постиже преко coroutineScope-а са async за сваки захтев.

kotlin
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())
}

Типичне грешке и ограниченja Async/Await-ја

Заборављени Task { } — асинхрону функцију не можете позвати из синхроног контекста без омотача у Task. У Swift-у се ово компајлира са грешком. У Kotlin-у је потребно покретање преко lifecycleScope-а или viewModelScope-а. Покушај позива suspend функције из обичне функције неће се компајлирати.

Прекомерна употреба async-а без потребе

Не треба сваку функцију чинити асинхроном. CPU-интензивне задатке без I/O не добијају предност од async-а — боље их је извршавати на DispatchQueue-у са .userInitiated QoS. Async/Await је оптимизован за I/O-bound операције: мрежа, диск, чекање.

Блокирање главне нити преко .result

Употреба .result на главној нити (синхроно чекање резултата async функције) доводи до блокирања. У Swift-у Task.synchronousWait Apple не препоручује. У Kotlin-у runBlocking на главној нити — антипатерн, користите lifecycleScope.

Цурење Task-а при отказивању

Ако се Task не сачува у својство класе, након изласка из контекста он се отказује. У Swift-у Task је scoped — његов животни циклус је везан за контекст који га је креирао. Чувајте Task у својству када је потребна дуготрајна операција.

Често постављана питања

По чему се async/await разликује од DispatchQueue-а?

Async/Await — језичка конструкција, не захтева креирање редова. DispatchQueue — системски API за управљање нитима. Async/await се компајлира у state machine на нивоу језика, GCD — у syscall на нивоу оперативног система.

Да ли await блокира нит?

Не — await суспендује функцију, али ослобађа нит за друге задатке. Након завршетка операције функција се наставља на било којој доступној нити из пула.

Може ли се отказати async задатак?

Да — преко Task.cancel() у Swift-у или Job.cancel() у Kotlin-у. Отказивање се проширује на све дочерње задатке према Structured Concurrency. Код сам проверава флаг отказивања преко Task.isCancelled или ensureActive().

Шта је MainActor у Swift-у?

MainActor — актор чија се својства и методе увек извршавају на главној нити. Обележавајући функцију @MainActor, гарантујете да се UI ажурирања дешавају на исправној нити, замењујући DispatchQueue.main.async.

У којим језицима постоји async/await?

Async/Await је доступан у Swift-у (iOS 13+), Kotlin-у (преко kotlinx.coroutines), Dart-у (Flutter), JavaScript/TypeScript, Python, C#, Rust-у и Go-у (преко goroutines-а са синтаксним шећером).

Резиме

  • Async/Await — језичка конструкција за линеарни асинхрони код без callback hell-а
  • Swift Concurrency пружа Task, TaskGroup, Actor и Structured Concurrency
  • Kotlin coroutines користе suspend функције, Dispatchers и корутинске scope-ове
  • Суспендовање без блокирања — кључна разлика async/await-ја од нити и редова
  • Structured Concurrency гарантује завршетак свих дочерњих задатака пре родитељске
  • Async/Await против GCD-ја — први је пожељнији за нови код, други — за legacy и low-level
  • MainActor у Swift-у и Dispatchers.Main у Kotlin-у штите UI нит од позадинских операција

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође