Async/Await: essentie, async functies en werken met await

Auteur: IT Sectr Gepubliceerd: 2026-03-16 Leestijd: 8 min

Async/Await is een paar trefwoorden voor het schrijven van asynchrone code in synchrone stijl, beschikbaar in Swift vanaf iOS 13 en in Kotlin met coroutines. Volgens Apple Swift Documentation, 2026 vervangt Async/Await callback-ketens en GCD, waardoor asynchrone code lineair en leesbaar wordt. Het trefwoord async markeert een functie als asynchroon, en await onderbreekt de uitvoering ervan totdat het resultaat is verkregen.

Belangrijkste punten

  • Async/Await — syntaxissuiker voor asynchrone code zonder geneste callbacks
  • async markeert een functie als asynchroon en onderbreekbaar
  • await onderbreekt de uitvoering van de functie totdat de asynchrone bewerking is voltooid
  • Task in Swift creëert een nieuwe asynchrone werkeenheid met context
  • Structured Concurrency zorgt dat alle onderliggende taken zijn voltooid voordat de bovenliggende taak eindigt

Wat is Async/Await en asynchroon programmeren

Async/Await is een taalconstructie waarmee je asynchrone code lineair kunt schrijven, net als synchrone code. In Swift is het beschikbaar vanaf iOS 13 / macOS 10.15 samen met het Swift Concurrency-framework. In Kotlin is async/await beschikbaar via de coroutine-bibliotheek (kotlinx.coroutines) vanaf versie 1.3.

Vóór async/await werd asynchrone code gebouwd met callbacks, GCD of RxSwift. Geneste callback-ketens leidden tot callback hell — diepe nesting die lezen en debuggen bemoeilijkt. Async/Await lost dit probleem op door asynchrone functies te laten "onderbreken" bij await-punten en te hervatten nadat het resultaat is verkregen.

Volgens Google (2025) vermindert het gebruik van async/await in Kotlin het aantal regels asynchrone code met 40–60% vergeleken met de callback-benadering. In Swift bereikte de adoptie van Swift Concurrency 68% onder gepubliceerde apps in 2025. iOS 16 voegde ondersteuning voor Swift Concurrency toe in UIKit, SwiftUI en Foundation, waardoor async/await de standaardtool werd voor alle nieuwe Apple-projecten.

Werkingsprincipe: onderbreekbare functies

Het belangrijkste verschil tussen async/await en threads is onderbreking zonder blokkering. Wanneer een functie await tegenkomt, wordt deze onderbroken, waardoor de huidige thread vrijkomt voor andere taken. Nadat de asynchrone bewerking is voltooid, wordt de functie hervat op dezelfde of een andere thread. Dit wordt cooperative multitasking genoemd.

Hoe werkt Async/Await: onderbreking en hervatting

Een async functie wordt gecompileerd tot een state machine — een finite state machine die de uitvoeringsstatus beheert. Op het await-punt slaat de compiler de context op (lokale variabelen, retouradres) en draagt de controle over aan de runtime. Wanneer het resultaat gereed is, herstelt de runtime de context en hervat de uitvoering.

In Swift is deze state machine geïmplementeerd op compilerniveau via SIL (Swift Intermediate Language). In Kotlin — via het Continuation Passing Style (CPS)-mechanisme: elke suspend-functie ontvangt een verborgen parameter Continuation, waarmee het resultaat wordt geretourneerd. Beide benaderingen garanderen veilige hervatting zonder geheugenlekken.

  • Swift — de compiler vertaalt async-functies naar SIL met een runAsync coroutine frame
  • Kotlin — elke suspend-functie ontvangt een Continuation en delegeert uitvoering aan de dispatcher
  • Beide talen — geven de thread vrij bij await, blokkeren deze niet tijdens het wachten
  • Uitzonderingen — worden afgehandeld via standaardmechanismen (throws / try-catch)

Async/Await vs Callbacks en GCD: vergelijking van benaderingen

De callback-benadering vereist het doorgeven van een closure die wordt aangeroepen nadat de bewerking is voltooid. Bij drie opeenvolgende verzoeken ontstaat drie niveaus van nesting met foutafhandeling op elk niveau. Async/Await verandert dezelfde drie verzoeken in drie opeenvolgende regels met een enkel catch-blok.

GCD (DispatchQueue) lost het callback-hell-probleem op via seriële wachtrijen en DispatchGroup, maar blijft omslachtig. Voor een eenvoudige taak — user laden, dan friends, dan UI — zijn het maken van wachtrijen, groepen en notify-blokken nodig. Async/Await voert dezelfde taak uit met drie regels in één functie.

AspectCallbackGCDAsync/Await
NestingDiep (pyramid of doom)Gemiddeld (groepen+notify)Lineair (flat)
FoutafhandelingPer-callbackHandmatigUniform (try/catch)
AnnuleringHandmatigBeperktTask.cancel()
Thread safetyHandmatigVia serial queueVia MainActor

Volgens Apple WWDC 2024 is Swift Concurrency async/await de aanbevolen benadering voor nieuwe code. GCD blijft voor integratie met C-bibliotheken en specifieke low-level scenario's voor threadverwerking.

Swift Concurrency: Task, TaskGroup en Actor

Task is de basiseenheid van asynchroon werk in Swift. Een Task wordt gemaakt in de context van een bestaande actor of op een willekeurige thread. Binnen een Task kunnen async-functies worden aangeroepen via await. TaskGroup maakt het mogelijk meerdere onderliggende taken parallel uit te voeren en hun resultaten te verzamelen — een krachtigere versie van DispatchGroup.

Actor is een thread-safe reference type dat zijn status beschermt tegen race conditions. De compiler garandeert dat toegang tot eigenschappen van een actor alleen mogelijk is via async-aanroepen of binnen actor-isolatie. Actor vervangt seriële DispatchQueue voor het beschermen van gedeelde veranderlijke status zonder handmatige vergrendelingen.

Structured Concurrency

Het principe van Structured Concurrency luidt: elke asynchrone taak heeft een ouder, en de ouder wordt niet voltooid voordat al zijn kinderen zijn voltooid. Als taak A Task { await B() } uitvoert, wacht A op B. Dit voorkomt taaklekkage en zorgt voor een voorspelbare levenscyclus.

Async/Await in Kotlin met coroutines

In Kotlin is async/await geïmplementeerd via coroutines — lichtgewicht threads van de taal. Een functie wordt gemarkeerd met het trefwoord suspend (analoog aan Swift's async). Voor uitvoering wordt launch (fire-and-forget) of async (met resultaat) gebruikt. Await wordt aangeroepen om het resultaat van async te verkrijgen.

Dispatcher bepaalt op welke threadpool de coroutine wordt uitgevoerd: Dispatchers.Main voor UI, Dispatchers.IO voor netwerk/schijf en Dispatchers.Default voor CPU-intensieve taken. Structured Concurrency wordt gegarandeerd via CoroutineScope — bij annulering van de scope worden alle onderliggende coroutines geannuleerd.

Volgens JetBrains (2025) gebruikt 97% van de Android-apps in Google Play kotlinx.coroutines, en 82% daarvan gebruikt async/await voor netwerkverzoeken. Coroutines zijn de de facto standaard geworden voor asynchroon programmeren in Android. Kotlin Multiplatform ondersteunt ook coroutines, waardoor gedeelde asynchrone code mogelijk is op Android, iOS en de serverkant.

Codevoorbeelden met Async/Await in Swift en Kotlin

Laten we twee voorbeelden bekijken voor elke taal: sequentiële gegevenslading en parallelle verzoeken met TaskGroup of async/await.

Swift: sequentiële async-aanroepen

await onderbreekt de uitvoering totdat gebruikersgegevens zijn verkregen, vervolgens totdat vrienden zijn verkregen. Geen geneste closures.

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: parallelle verzoeken met TaskGroup

TaskGroup voert taken parallel uit en verzamelt de resultaten in een array. De volgorde van resultaten kan afwijken van de startvolgorde.

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: sequentiële aanroep met async/await

suspend-functies kunnen andere suspend-functies aanroepen. Analoog aan Swift: sequentiële aanroepen.

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

Kotlin: parallelle verzoeken met async/await

In Kotlin wordt parallellisme bereikt via coroutineScope met async voor elk verzoek.

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

Veelvoorkomende fouten en beperkingen van Async/Await

Vergeten Task { } — een asynchrone functie kan niet worden aangeroepen vanuit een synchrone context zonder deze in een Task te verpakken. In Swift resulteert dit in een compilatiefout. In Kotlin is uitvoering via lifecycleScope of viewModelScope vereist. Het aanroepen van een suspend-functie vanuit een gewone functie wordt niet gecompileerd.

Overmatig gebruik van async zonder noodzaak

Niet elke functie hoeft asynchroon te worden gemaakt. CPU-intensieve taken zonder I/O hebben geen baat bij async — ze kunnen beter worden uitgevoerd op een DispatchQueue met .userInitiated QoS. Async/Await is geoptimaliseerd voor I/O-gebonden bewerkingen: netwerk, schijf, wachten.

Blokkeren van de hoofdthread via .result

Het gebruik van .result op de hoofdthread (synchroon wachten op het resultaat van een async-functie) leidt tot blokkering. In Swift wordt Task.synchronousWait niet aanbevolen door Apple. In Kotlin is runBlocking op de hoofdthread een antipatroon — gebruik lifecycleScope.

Taaklekkage bij annulering

Als een Task niet wordt opgeslagen in een klasseeigenschap, wordt deze geannuleerd na het verlaten van de context. In Swift is Task scoped — de levenscyclus is gekoppeld aan de aanmaakcontext. Bewaar de Task in een eigenschap als een langdurige bewerking nodig is.

Veelgestelde vragen

Wat is het verschil tussen async/await en DispatchQueue?

Async/Await is een taalconstructie die geen wachtrijen vereist. DispatchQueue is een systeem-API voor threadbeheer. Async/await wordt gecompileerd naar een state machine op taalniveau, GCD naar een syscall op OS-niveau.

Blokkeert await de thread?

Nee — await onderbreekt de functie, maar geeft de thread vrij voor andere taken. Na voltooiing van de bewerking wordt de functie hervat op een beschikbare thread uit de pool.

Kan een asynchrone taak worden geannuleerd?

Ja — via Task.cancel() in Swift of Job.cancel() in Kotlin. Annulering verspreidt zich naar alle onderliggende taken volgens Structured Concurrency. De code controleert de annuleringsvlag via Task.isCancelled of ensureActive().

Wat is MainActor in Swift?

MainActor is een actor waarvan eigenschappen en methoden altijd op de hoofdthread worden uitgevoerd. Door een functie te markeren met @MainActor garandeer je dat UI-updates op de juiste thread plaatsvinden, ter vervanging van DispatchQueue.main.async.

In welke talen is async/await beschikbaar?

Async/Await is beschikbaar in Swift (iOS 13+), Kotlin (via kotlinx.coroutines), Dart (Flutter), JavaScript/TypeScript, Python, C#, Rust en Go (via goroutines met syntaxissuiker).

Samenvatting

  • Async/Await — taalconstructie voor lineaire asynchrone code zonder callback hell
  • Swift Concurrency biedt Task, TaskGroup, Actor en Structured Concurrency
  • Kotlin coroutines gebruiken suspend-functies, Dispatchers en coroutine-scopes
  • Onderbreking zonder blokkering — het belangrijkste verschil tussen async/await en threads/wachtrijen
  • Structured Concurrency garandeert voltooiing van alle onderliggende taken vóór de bovenliggende taak
  • Async/Await vs GCD — eerste heeft de voorkeur voor nieuwe code, tweede voor legacy en low-level
  • MainActor in Swift en Dispatchers.Main in Kotlin beschermen de UI-thread tegen achtergrondbewerkingen

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook