Propagation des exceptions avec async/await
Comprenez comment les exceptions issues de async se propagent et quand utiliser try-await.
Propagation des exceptions avec async/await est une leçon Kotlin Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Kotlin Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Kotlin Academy comprend 4 leçons au total.
L'asynchronisme stocke les exceptions
Contrairement à launch, async stocke l'exception dans le Deferred renvoyé. Elle n'est relancée que lorsque vous appelez await().
import kotlinx.coroutines.*
fun main() = runBlocking {
val deferred = async {
throw RuntimeException("async error")
}
try {
deferred.await() // exception rethrown here
} catch (e: RuntimeException) {
println("Caught: ${e.message}")
}
}Exception sans appel à await()
Si vous n'appelez jamais await(), l'exception est silencieusement ignorée avec un parent Job ordinaire. Préférez supervisorScope et attendez toujours les résultats.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Exception stored in deferred, never retrieved:
val d = async { throw RuntimeException("lost exception") }
delay(100) // d has failed — exception never surfaced
println("d.isCancelled: ${d.isCancelled}")
}Asynchronisme dans une portée de coroutine
Dans une coroutineScope ordinaire, si un enfant asynchrone lève une exception qui se propage parce qu'elle n'est pas interceptée, la portée et tous ses frères sont annulés.
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
coroutineScope {
val a = async { "A" }
val b = async { throw RuntimeException("B failed") }
println(a.await())
println(b.await()) // propagates, cancels scope
}
} catch (e: RuntimeException) {
println("Scope failed: ${e.message}")
}
}Asynchronisme dans une portée de supervision
Dans supervisorScope, les exceptions de async ne se propagent NOT pas aux frères. Chaque await()` doit être encapsulé individuellement.
import kotlinx.coroutines.*
fun main() = runBlocking {
supervisorScope {
val a = async { "A" }
val b = async { throw RuntimeException("B failed") }
println(a.await())
try { println(b.await()) }
catch (e: RuntimeException) { println("b failed: ${e.message}") }
}
}awaitAll pour plusieurs opérations asynchrones
awaitAll(d1, d2, d3) attend tous les différés. En cas d'échec de l'un d'eux, il lève immédiatement une exception et annule les autres.
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
val results = awaitAll(
async { "result1" },
async { throw RuntimeException("task 2 failed") },
async { "result3" }
)
println(results)
} catch (e: Exception) {
println("awaitAll failed: ${e.message}")
}
}runCatching avec des opérations asynchrones
Entourez chaque appel à await() de runCatching pour recueillir les résultats et les erreurs sans interrompre le traitement au premier échec.
import kotlinx.coroutines.*
fun main() = runBlocking {
supervisorScope {
val deferreds = listOf(
async { "A" },
async { throw RuntimeException("B") },
async { "C" }
)
val results = deferreds.map { runCatching { it.await() } }
results.forEach { println(it) }
}
}Tâches parallèles avec accumulation des erreurs
Recueillez tous les échecs des tâches asynchrones parallèles et signalez-les ensemble plutôt que d'échouer dès le premier problème.
import kotlinx.coroutines.*
fun main() = runBlocking {
val tasks = listOf("a", "b", "c")
val results = supervisorScope {
tasks.map { t ->
async {
if (t == "b") throw RuntimeException("b failed")
t.uppercase()
}
}.map { runCatching { it.await() } }
}
val errors = results.filter { it.isFailure }
val successes = results.mapNotNull { it.getOrNull() }
println("Success: $successes, Errors: ${errors.size}")
}Préservation du type d'exception
Les exceptions levées dans async conservent leur type. Interceptez le type d'exception précis lors de l'appel à await() pour gérer les erreurs avec précision.
import kotlinx.coroutines.*
class NetworkException(msg: String) : RuntimeException(msg)
fun main() = runBlocking {
val d = async { throw NetworkException("timeout") }
try {
d.await()
} catch (e: NetworkException) {
println("Network error: ${e.message}")
} catch (e: Exception) {
println("Other error: ${e.message}")
}
}Deferred.getCompleted() pour une vérification synchrone
Après join(), utilisez getCompleted() pour récupérer le résultat de manière synchrone. Cette fonction lève une exception si le différé a échoué.
import kotlinx.coroutines.*
fun main() = runBlocking {
val d = async { 42 }
d.join() // wait without caring about result
try {
val result = d.getCompleted() // synchronous — no suspend
println("Result: $result")
} catch (e: Exception) {
println("Failed: ${e.message}")
}
}Concurrence structurée et opérations asynchrones
Avec la concurrence structurée, un différé async est toujours lié à sa portée parent. Lorsque la portée est annulée, le différé l'est également : aucune tâche orpheline.
import kotlinx.coroutines.*
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob())
val d = scope.async {
delay(1000)
"result"
}
scope.cancel() // cancels d too
try { d.await() }
catch (e: CancellationException) { println("Cancelled as expected") }
}Bonne pratique : attendez toujours les résultats
Appelez toujours await() pour chaque différé async, même si vous n'avez pas besoin du résultat. Cela fait apparaître les exceptions et évite les échecs silencieux.
import kotlinx.coroutines.*
fun main() = runBlocking {
supervisorScope {
val d = async {
// do background work
"done"
}
// Always await:
val result = runCatching { d.await() }
println(result)
}
}Vérification rapide
Quand l'exception du bloc async { throw ... } apparaît-elle ?
Récapitulatif
async stocke les exceptions dans le Deferred ; elles apparaissent lors de l'appel à await(). Avec coroutineScope, leur propagation annule les frères. Avec supervisorScope, chaque appel à await() doit gérer son propre échec. Attendez toujours chaque différé.
Questions Fréquemment Posées
La leçon « Propagation des exceptions avec async/await » est-elle gratuite ?
Oui — le texte complet de « Propagation des exceptions avec async/await » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Kotlin Academy, passe à CoddyKit PRO. Le cours Kotlin Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Propagation des exceptions avec async/await » ?
Comprenez comment les exceptions issues de async se propagent et quand utiliser try-await. Tu pratiques Kotlin Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Kotlin Academy ?
Aucune expérience préalable n'est requise. Kotlin Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Propagation des exceptions avec async/await » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Kotlin Academy ?
Oui. Chaque leçon Kotlin Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- SupervisorJob ou Job : isolation des échecs
- CoroutineExceptionHandler : gestionnaire global des exceptions non interceptées
- Propagation des exceptions avec async/await
- Concevoir des architectures de coroutines résilientes