suspend function: wat is het, syntax en werking in coroutines

Auteur: IT Sectr Gepubliceerd: 2026-06-22 Leestijd: 9 min

Suspend function — is een functie met de suspend-modifier die de uitvoering kan onderbreken zonder de thread te blokkeren en later kan hervatten in dezelfde coroutine. Volgens JetBrains Kotlin Docs, 2025 zijn suspend-functies de fundamentele bouwstenen van coroutines en bieden ze asynchroniteit zonder callbacks. Elke suspend-functie wordt gecompileerd naar een op Continuation gebaseerde toestandsmachine, waardoor suspensiepunten efficiënt kunnen worden beheerd.

Belangrijkste punten

  • Suspend — Kotlin sleutelwoord dat een functie markeert als onderbreekbaar (asynchroon)
  • Continuation — verborgen parameter die de compiler aan elke suspend-functie toevoegt om de status te bewaren
  • Suspensiepunten — plaatsen waar andere suspend-functies worden aangeroepen, waar de coroutine kan stoppen zonder te blokkeren
  • Toestandsmachine — interne representatie van een suspend-functie, waarbij elk suspensiepunt een aparte toestand is
  • Alleen vanuit coroutine aanroepen — suspend-functies kunnen alleen worden aangeroepen vanuit een andere suspend-functie of vanuit launch/async

Wat is een suspend function in Kotlin?

Suspend function — is een functie gedeclareerd met het sleutelwoord suspend die de uitvoering kan onderbreken op een of meer punten zonder de thread te blokkeren. Elke aanroep van een suspend-functie binnen een andere suspend-functie is een potentieel suspensiepunt.

kotlin
suspend fun fetchUserData(): User {
    val response = httpClient.get("/user")
    return parser.parse(response)
}

De Kotlin-compiler vertaalt zo'n functie naar een toestandsmachine. Elk suspensiepunt (aanroep van een andere suspend-functie) wordt een toestand (label). De huidige thread wordt vrijgegeven tussen toestanden en na voltooiing van de verwachte bewerking wordt de uitvoering hervat vanuit de volgende toestand.

Geschiedenis van ontstaan

Suspend-functies verschenen in Kotlin 1.3 (2018) samen met coroutines als een experimentele functie en werden stabiel in Kotlin 1.5 (2021). Daarvoor werd asynchroniteit in Kotlin/Java verzorgd door callbacks, RxJava en CompletableFuture. Suspend-functies boden een alternatief met lineaire syntax en automatisch threadbeheer.

Hoe werken suspend-functies: Continuation en toestandsmachine

Inzicht in de interne structuur van suspend-functies is de sleutel tot correct werken met coroutines. In tegenstelling tot gewone functies wordt elke suspend-functie gecompileerd naar een klasse met de Continuation-interface.

Continuation — de verborgen parameter

De Kotlin-compiler voegt een parameter van het type Continuation toe aan het einde van elke parameter van een suspend-functie. Continuation bevat:

  • context — CoroutineContext (dispatcher, job, context-elementen)
  • resumeWith — methode om de uitvoering te hervatten met een resultaat of uitzondering
  • label — index van de huidige toestand in de toestandsmachine

Toestandsmachine met voorbeeld

Stel dat we een suspend-functie hebben met twee aanroepen naar andere suspend-functies:

kotlin
suspend fun process() {
    val a = stepOne()
    val b = stepTwo(a)
    println(b)
}

De compiler zet dit om in een toestandsmachine met labels:

kotlin
// Vereenvoudigde weergave van gegenereerde code
fun process(cont: Continuation<Unit>): Any? {
    val cont = cont as ProcessContinuation
    when (cont.label) {
        0 -> {
            cont.label = 1
            if (stepOne(cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
        }
        1 -> {
            cont.label = 2
            val a = cont.result as TypeA
            if (stepTwo(a, cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
        }
        2 -> {
            println(cont.result)
            Unit
        }
    }
}

Belangrijke observatie: als de functie COROUTINE_SUSPENDED retourneert, wordt de huidige thread vrijgegeven. Wanneer de asynchrone bewerking is voltooid, wordt Continuation.resumeWith aangeroepen en gaat de toestandsmachine verder vanaf het volgende label.

Syntax van suspend-functies: declaratie en aanroep

De declaratie van een suspend-functie verschilt niet van een gewone, behalve het sleutelwoord suspend voor fun. Er is slechts één beperking: een suspend-functie kan alleen worden aangeroepen vanuit een coroutine of een andere suspend-functie.

Basisdeclaratie

kotlin
suspend fun delayAndReturn(ms: Long): String {
    delay(ms)
    return "Done after ${ms}ms"
}

In dit voorbeeld is delay ook een suspend-functie die de coroutine onderbreekt voor een opgegeven aantal milliseconden zonder de thread te blokkeren. Na de vertraging wordt de uitvoering hervat.

Aanroep vanuit een coroutine

kotlin
fun main() = runBlocking {
    val result = delayAndReturn(1000)
    println(result)
}

runBlocking creëert een brug tussen de gewone wereld en coroutines. Binnen de lambda is het aanroepen van elke suspend-functie toegestaan.

Suspend-lambdas en functionele typen

Kotlin ondersteunt suspend-versies van functionele typen — suspend () -> T en suspend (A) -> B. Dit maakt het mogelijk asynchrone lambdas door te geven aan functies van hogere orde:

kotlin
suspend fun  withRetry(
    retries: Int = 3,
    block: suspend () -> T
): T {
    repeat(retries - 1) {
        try { return block() }
        catch (_: Exception) { delay(100) }
    }
    return block()
}

De functie withRetry accepteert een suspend-lambda en herhaalt de uitvoering bij fouten. Dit is een typisch patroon voor netwerkverzoeken met herpogingen.

Hoe verschillen suspend-functies van gewone

De verschillen tussen suspend en gewone functies gaan verder dan het eenvoudig toevoegen van een modifier. Laten we de fundamentele verschillen bekijken.

KenmerkGewone functieSuspend-functie
UitvoeringsthreadBlokkeert de thread tot voltooiingKan thread vrijgeven en later hervatten
CompilerparametersAlleen opgegeven parametersImpliciete Continuation aan het einde
Aanroep vanuit gewone functieJaNee
StackFysieke thread-stackToestandsmachine op heap + fysieke stack tussen punten
ReturnDirecte waardeWaarde of COROUTINE_SUSPENDED
PrestatiesMinimale overhead~enkele nanoseconden voor toestandsmachine (Kotlin 1.9+)

Waarom suspend-functies niet vanuit gewone functies kunnen worden aangeroepen

Een gewone functie heeft geen Continuation — geen plek om de status op te slaan en de uitvoering te hervatten. Als u een suspend-functie vanuit een gewone functie moet aanroepen, gebruik dan runBlocking (voor tests) of CoroutineScope.launch (voor productie met inachtneming van de levenscyclus).

Voorbeelden van suspend-functies in Android

Laten we drie realistische scenario's bekijken voor het gebruik van suspend-functies in Android-apps met Kotlin.

Voorbeeld 1: Room DAO met suspend-query's

Room ondersteunt suspend-functies direct — de query wordt automatisch op de achtergrond uitgevoerd:

kotlin
@Dao
interface UserDao {
    @Query("SELECT * FROM users WHERE id = :id")
    suspend fun getUser(id: Int): User?

    @Insert
    suspend fun insertUser(user: User)
}

Room gebruikt intern Dispatchers.IO voor het uitvoeren van de query en het resultaat wordt teruggegeven aan de dispatcher waarin de suspend-functie werd aangeroepen.

Voorbeeld 2: Compositie van suspend-functies voor scherm laden

kotlin
class ProfileViewModel : ViewModel() {
    private val repo = ProfileRepository()

    fun loadProfile(id: String) {
        viewModelScope.launch {
            val profile = repo.getProfile(id)
            _profile.value = profile
        }
    }
}

ViewModelScope.launch creëert een coroutine waarbinnen de suspend-functie getProfile wordt aangeroepen. Nadat het resultaat is verkregen, wordt de UI bijgewerkt op de hoofdthread.

Voorbeeld 3: Opeenvolgende asynchrone stappen

kotlin
suspend fun placeOrder(cart: Cart): OrderResult {
    val validated = validateCart(cart)
    val payment = processPayment(validated)
    val receipt = sendReceipt(payment)
    return receipt
}

Drie suspend-functies worden opeenvolgend uitgevoerd. Bij elke stap kan de coroutine stoppen zonder de thread te blokkeren. Als een stap een uitzondering genereert — worden de andere niet uitgevoerd, wat beschermt tegen onjuiste bestelstatussen.

Veelgemaakte fouten bij het werken met suspend-functies

Zelfs ervaren Kotlin-ontwikkelaars maken fouten bij het ontwerpen van suspend-functies. Laten we de meest voorkomende bekijken.

Fout 1: Blokkerende aanroepen binnen suspend

Een suspend-functie maakt code niet automatisch asynchroon. Thread.sleep(), InputStream.read() en andere blokkerende aanroepen blokkeren nog steeds de thread. Gebruik withContext(Dispatchers.IO) om blokkerende bewerkingen in te pakken.

Fout 2: Onnodig aanmaken van suspend-functies

Als een functie geen andere suspend-functies aanroept en geen asynchrone bewerkingen uitvoert — is de suspend-modifier overbodig. Het voegt overhead toe aan de toestandsmachine en beperkt de aanroepcontext. Maak een functie alleen suspend als deze daadwerkelijk onderbroken wordt.

Fout 3: Negeren van CancellationException

Bij het annuleren van een coroutine gooien suspend-functies een CancellationException. Vang deze niet gedachteloos — u ontneemt de aanroepende code de mogelijkheid om de annulering correct af te ronden. Als u een finaliserende bewerking moet uitvoeren, gebruik dan een finally-blok en NonCancellable.

kotlin
suspend fun safeOperation() {
    try {
        doWork()
    } finally {
        withContext(NonCancellable) {
            cleanup()
        }
    }
}

Het finally-blok wordt altijd uitgevoerd, inclusief bij annulering, en NonCancellable garandeert dat de opschoning niet wordt onderbroken.

Fout 4: Aanroepen van suspend-functies vanuit callbacks

Een suspend-functie kan niet direct vanuit een callback worden aangeroepen zonder een coroutine te maken. Gebruik suspendCoroutine of suspendCancellableCoroutine om de callback-stijl aan te passen aan coroutines.

Veelgestelde vragen

Kan een suspend-functie geen suspensiepunten bevatten?

Ja, technisch gezien kan een suspend-functie andere suspend-functies niet aanroepen. De compiler maakt een toestandsmachine met één toestand (label 0). Zo'n functie heeft echter geen praktisch nut — hij wordt uitgevoerd als een gewone, maar met overhead. Gebruik suspend niet onnodig.

Hoe debug ik suspend-functies?

Kotlin biedt kotlinx-coroutines-debug — een bibliotheek met DebugProbes en hulpmiddelen voor het traceren van coroutines. In Android Studio vanaf versie Arctic Fox is er een ingebouwd Coroutines-tabblad in de Debugger dat actieve coroutines, hun status en suspensiepunten toont.

Beïnvloedt het aantal suspend-punten de prestaties?

Elk suspensiepunt creëert een nieuwe toestand in de toestandsmachine. Voor de meeste toepassingen bedraagt de overhead van één punt enkele nanoseconden (Kotlin 1.9+). Alleen bij tienduizenden punten in een lus is het de moeite waard om bewerkingen te combineren of sequence/flow te gebruiken.

Waarin verschilt een suspend-functie van async/await in andere talen?

In Kotlin is suspend een modifier van het functietype, geen markering van de retourwaarde (zoals async in C#). Elke suspend-functie kan willekeurige parameters en retourtypen hebben en de aanroep ervan verschilt syntactisch niet van een gewone functieaanroep — er is geen await-operator op de aanroepplaats.

Hoe converteer ik een callback-functie naar suspend?

Gebruik suspendCancellableCoroutine voor aanpassing. Binnenin geeft u de callback-registratie door die continuation.resume() aanroept en retourneert u een annuleringstoken als de callback uitschrijven ondersteunt. Dit is een standaardpatroon voor het inpakken van oude Android-API's.

Samenvatting

  • Suspend function — functie met de suspend-modifier die de uitvoering kan onderbreken zonder de thread te blokkeren via het Continuation-mechanisme
  • Toestandsmachine — interne representatie van een suspend-functie in Kotlin-bytecode, waarbij elk suspensiepunt een aparte toestand met een label is
  • Continuation — verborgen parameter die de coroutine-context en de resumeWith-methode bevat voor het hervatten van de uitvoering
  • Alleen vanuit coroutine aanroepen — suspend-functies zijn niet toegankelijk vanuit gewone functies zonder runBlocking of CoroutineScope
  • Blokkerende bewerkingen binnen suspend vereisen withContext(Dispatchers.IO) — anders wordt de thread geblokkeerd
  • Room en Retrofit ondersteunen suspend-functies natively en beheren automatisch achtergrondthreads
  • CancellationException — behandel annulering via finally + NonCancellable, vang CancellationException niet gedachteloos

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