suspend function : définition, syntaxe et fonctionnement dans les coroutines

Auteur : IT Sectr Publié le : 2026-06-22 Temps de lecture : 9 min

Suspend function est une fonction avec le modificateur suspend qui peut suspendre son exécution sans bloquer un thread et reprendre plus tard dans la même coroutine. Selon JetBrains Kotlin Docs, 2025, les fonctions suspend sont un bloc fondamental des coroutines, offrant l'asynchronisme sans callbacks. Chaque fonction suspend est compilée en une machine d'état basée sur Continuation, permettant une gestion efficace des points de suspension.

Points clés

  • Suspend — mot-clé Kotlin qui marque une fonction comme suspendable (asynchrone)
  • Continuation — paramètre caché que le compilateur ajoute à chaque fonction suspend pour sauvegarder l'état
  • Points de suspension — endroits où d'autres fonctions suspend sont appelées, où une coroutine peut s'arrêter sans bloquer
  • Machine d'état — représentation interne d'une fonction suspend, où chaque point de suspension est un état séparé
  • Appel depuis une coroutine uniquement — les fonctions suspend ne peuvent être appelées que depuis une autre fonction suspend ou depuis launch/async

Qu'est-ce qu'une suspend function en Kotlin ?

Suspend function est une fonction déclarée avec le mot-clé suspend qui peut suspendre l'exécution à un ou plusieurs points sans bloquer le thread. Chaque appel à une fonction suspend à l'intérieur d'une autre fonction suspend est un point de suspension potentiel.

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

Le compilateur Kotlin traduit une telle fonction en machine d'état. Chaque point de suspension (un appel à une autre fonction suspend) devient un état (label). Le thread actuel est libéré entre les états, et une fois l'opération attendue terminée, l'exécution reprend à partir de l'état suivant.

Historique

Les fonctions suspend sont apparues dans Kotlin 1.3 (2018) avec les coroutines en tant que fonctionnalité expérimentale et sont devenues stables dans Kotlin 1.5 (2021). Avant cela, l'asynchronisme en Kotlin/Java était réalisé via des callbacks, RxJava et CompletableFuture. Les fonctions suspend ont offert une alternative avec une syntaxe linéaire et une gestion automatique des threads.

Comment fonctionnent les fonctions suspend : Continuation et machine d'état

Comprendre le fonctionnement interne des fonctions suspend est la clé pour travailler correctement avec les coroutines. Contrairement aux fonctions classiques, chaque fonction suspend est compilée en une classe avec l'interface Continuation.

Continuation — le paramètre caché

Le compilateur Kotlin ajoute un paramètre de type Continuation à la fin de chaque liste de paramètres d'une fonction suspend. Continuation contient :

  • context — CoroutineContext (dispatcher, job, éléments de contexte)
  • resumeWith — méthode pour reprendre l'exécution avec un résultat ou une exception
  • label — index de l'état actuel dans la machine d'état

Exemple de machine d'état

Supposons que nous ayons une fonction suspend avec deux appels à d'autres fonctions suspend :

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

Le compilateur la transforme en une machine d'état avec des étiquettes :

kotlin
// Simplified generated code representation
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
        }
    }
}

Observation clé : si la fonction retourne COROUTINE_SUSPENDED, le thread actuel est libéré. Lorsque l'opération asynchrone se termine, Continuation.resumeWith est appelé et la machine d'état continue à partir de l'étiquette suivante.

Syntaxe des fonctions suspend : déclaration et invocation

Déclarer une fonction suspend n'est pas différent d'une fonction classique, sauf pour le mot-clé suspend avant fun. Il y a seulement une restriction : une fonction suspend ne peut être appelée que depuis une coroutine ou une autre fonction suspend.

Déclaration de base

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

Dans cet exemple, delay est aussi une fonction suspend qui suspend la coroutine pendant le nombre spécifié de millisecondes sans bloquer le thread. Après le délai, l'exécution reprend.

Appel depuis une coroutine

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

runBlocking crée un pont entre le monde classique et les coroutines. À l'intérieur du lambda, n'importe quelle fonction suspend peut être appelée.

Lambdas suspend et types fonctionnels

Kotlin prend en charge les versions suspend des types fonctionnels — suspend () -> T et suspend (A) -> B. Cela permet de passer des lambdas asynchrones aux fonctions d'ordre supérieur :

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

La fonction withRetry prend un lambda suspend et réessaie son exécution en cas d'erreur. C'est un modèle typique pour les requêtes réseau avec tentatives.

Différences entre fonctions suspend et fonctions classiques

Les différences entre les fonctions suspend et classiques vont au-delà de la simple ajout d'un modificateur. Examinons les distinctions principales.

CaractéristiqueFonction classiqueFonction suspend
Thread d'exécutionBloque le thread jusqu'à la finPeut libérer le thread et reprendre plus tard
Paramètres compilateurUniquement les paramètres spécifiésContinuation implicite à la fin
Appel depuis fonction classiqueOuiNon
PilePile physique du threadMachine d'état dans le heap + pile physique entre les points
Valeur de retourValeur directeValeur ou COROUTINE_SUSPENDED
PerformanceSurcharge minimale~quelques nanosecondes par machine d'état (Kotlin 1.9+)

Pourquoi les fonctions suspend ne peuvent pas être appelées depuis des fonctions classiques

Une fonction classique n'a pas de Continuation — elle n'a nulle part où sauvegarder l'état et rien pour reprendre l'exécution. Si vous devez appeler une fonction suspend depuis une fonction classique, utilisez runBlocking (pour les tests) ou CoroutineScope.launch (pour la production avec conscience du cycle de vie).

Exemples de fonctions suspend sous Android

Examinons trois scénarios réels d'utilisation des fonctions suspend dans les applications Android avec Kotlin.

Exemple 1 : Room DAO avec requêtes suspend

Room prend en charge les fonctions suspend directement — la requête est exécutée automatiquement sur un thread d'arrière-plan :

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

    @Insert
    suspend fun insertUser(user: User)
}

Room utilise en interne Dispatchers.IO pour exécuter la requête, et le résultat est retourné sur le dispatcher où la fonction suspend a été appelée.

Exemple 2 : Composition de fonctions suspend pour le chargement d'écran

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

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

ViewModelScope.launch crée une coroutine, à l'intérieur de laquelle la fonction suspend getProfile est appelée. Après avoir obtenu le résultat, l'interface utilisateur est mise à jour sur le thread principal.

Exemple 3 : Étapes asynchrones séquentielles

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

Trois fonctions suspend s'exécutent séquentiellement. À chaque étape, la coroutine peut se suspendre sans bloquer le thread. Si une étape lève une exception, les étapes restantes ne s'exécutent pas, protégeant contre des états de commande incorrects.

Erreurs courantes avec les fonctions suspend

Même les développeurs Kotlin expérimentés commettent des erreurs lors de la conception de fonctions suspend. Examinons les plus courantes.

Erreur 1 : Appels bloquants dans suspend

Une fonction suspend ne rend pas le code automatiquement asynchrone. Thread.sleep(), InputStream.read() et autres appels bloquants continueront de bloquer le thread. Utilisez withContext(Dispatchers.IO) pour encapsuler les opérations bloquantes.

Erreur 2 : Créer des fonctions suspend inutilement

Si une fonction n'appelle pas d'autres fonctions suspend et n'effectue pas d'opérations asynchrones — le modificateur suspend est redondant. Il ajoute une surcharge à la machine d'état et restreint le contexte d'appel. Ne rendez une fonction suspend que lorsqu'elle se suspend réellement.

Erreur 3 : Ignorer CancellationException

Lorsqu'une coroutine est annulée, les fonctions suspend lancent CancellationException. Ne l'attrapez pas sans réfléchir — vous privez le code appelant de la capacité à terminer correctement l'annulation. Si vous devez effectuer une opération de finalisation, utilisez un bloc finally et NonCancellable.

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

Le bloc finally s'exécute toujours, y compris lors de l'annulation, et NonCancellable garantit que le nettoyage ne sera pas interrompu.

Erreur 4 : Appeler des fonctions suspend depuis des callbacks

Vous ne pouvez pas appeler une fonction suspend directement depuis un callback sans créer une coroutine. Utilisez suspendCoroutine ou suspendCancellableCoroutine pour adapter le style callback aux coroutines.

Questions fréquentes

Une fonction suspend peut-elle n'avoir aucun point de suspension ?

Oui, techniquement une fonction suspend peut ne pas appeler d'autres fonctions suspend. Le compilateur créera une machine d'état avec un seul état (label 0). Cependant, une telle fonction n'a aucun intérêt pratique — elle s'exécute comme une fonction classique mais avec une surcharge. N'utilisez pas suspend inutilement.

Comment déboguer les fonctions suspend ?

Kotlin fournit kotlinx-coroutines-debug — une bibliothèque avec DebugProbes et des outils de traçage de coroutines. Dans Android Studio à partir d'Arctic Fox, il y a un onglet Coroutines intégré dans le Débogueur qui montre les coroutines actives, leur état et les points de suspension.

Le nombre de points de suspension affecte-t-il les performances ?

Chaque point de suspension crée un nouvel état dans la machine d'état. Pour la plupart des applications, la surcharge d'un point est de quelques nanosecondes (Kotlin 1.9+). Ce n'est qu'avec des dizaines de milliers de points dans une boucle que vous devriez envisager de combiner des opérations ou d'utiliser sequence/flow.

En quoi une fonction suspend diffère-t-elle de async/await dans d'autres langages ?

En Kotlin, suspend est un modificateur de type de fonction, pas un marqueur de valeur de retour (comme async en C#). Toute fonction suspend peut avoir n'importe quels paramètres et type de retour, et son appel ne diffère pas syntaxiquement d'un appel de fonction classique — il n'y a pas d'opérateur await au point d'appel.

Comment convertir une fonction callback en suspend ?

Utilisez suspendCancellableCoroutine pour l'adaptation. À l'intérieur, vous enregistrez un callback qui appelle continuation.resume(), et retournez un jeton d'annulation si le callback prend en charge le désabonnement. C'est le modèle standard pour encapsuler les anciennes API Android.

Résumé

  • Suspend function — fonction avec le modificateur suspend qui peut suspendre l'exécution sans bloquer un thread via le mécanisme Continuation
  • Machine d'état — représentation interne d'une fonction suspend en bytecode Kotlin, où chaque point de suspension est un état séparé avec une étiquette
  • Continuation — paramètre caché contenant le contexte de la coroutine et la méthode resumeWith pour reprendre l'exécution
  • Appel depuis coroutine uniquement — les fonctions suspend ne sont pas accessibles depuis les fonctions classiques sans runBlocking ou CoroutineScope
  • Opérations bloquantes dans suspend nécessitent withContext(Dispatchers.IO) — sinon le thread se bloque
  • Room et Retrofit prennent en charge nativement les fonctions suspend, gérant automatiquement les threads d'arrière-plan
  • CancellationException — gérez l'annulation via finally + NonCancellable, n'attrapez pas CancellationException sans réfléchir

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi