Future/Promise — définition, calculs asynchrones et programmation

Auteur : IT Sectr Publié le : 2026-03-17 Temps de lecture : 9 min

Future/Promise est un motif de programmation asynchrone qui représente un conteneur pour le résultat d’une opération pas encore terminée. Selon Dart Documentation, 2025, Future est un résultat en lecture seule de calculs différés, Promise est un contrat en écriture seule qui remplit ce résultat. Future est utilisé en Dart, Java, Scala et C++ pour les chaînes then/catch.

Points clés

  • Future — un conteneur en lecture seule pour un résultat asynchrone disponible dans le futur
  • Promise — un espace réservé en écriture seule qui accepte le résultat et le transmet au Future
  • Chaînes then — traitement séquentiel d’opérations asynchrones sans callbacks imbriqués
  • Future en Dart — la base d’async/await et des bibliothèques dio, http, shelf
  • Future/Promise — une alternative au motif callback et la base de la syntaxe async/await

Qu’est-ce que Future/Promise ?

Future/Promise est une paire d’objets interconnectés qui divisent un résultat asynchrone en deux rôles. Promise peut écrire le résultat (resolve) ou une erreur (reject). Future peut seulement le lire — via des callbacks (then, catchError) ou via await. Cette séparation garantit que le consommateur ne peut pas modifier le résultat, seulement l’utiliser.

Future en Dart

Le langage Dart utilise Future comme son principal mécanisme asynchrone. Future<T> est un contrat pour recevoir une valeur de type T dans le futur. Un Future peut être dans l’un des trois états : unresolved (opération en cours), resolved with value (terminé avec succès) ou resolved with error (terminé avec erreur). Une fois passé à l’état resolved, le Future ne change jamais.

Promise en JavaScript

Promise en JavaScript est analogue au Future de Dart, mais avec une API plus riche. Promise prend un exécuteur — une fonction avec les paramètres resolve et reject. Les méthodes statiques Promise.all, Promise.race, Promise.allSettled permettent de combiner plusieurs promesses. Les applications modernes utilisent la syntaxe async/await au-dessus de Promise.

Comment fonctionne Future

Future fonctionne sur la base d’une boucle d’événements (event loop) — un cycle d’événements qui traite les opérations asynchrones sans bloquer le thread principal. Lorsqu’une fonction asynchrone est appelée (par exemple, http.get), elle retourne immédiatement un Future. La requête réelle s’exécute en arrière-plan, tandis que la boucle d’événements continue de traiter d’autres événements. Après la fin de l’opération, le Future passe à l’état resolved et then est appelé.

La boucle d’événements est le mécanisme clé sur lequel Dart et JavaScript sont construits. La boucle d’événements maintient deux files : la file des microtâches (tâches courtes, exécutées avant l’événement suivant) et la file des événements (événements IO, temporisateurs). Future.then place un callback dans la file des microtâches, Future.microtask — exécution prioritaire avant l’image suivante.

Les chaînes de then() permettent de traiter séquentiellement les résultats d’opérations asynchrones sans enfer des callbacks. Chaque then() reçoit le résultat de l’étape précédente et retourne un nouveau Future. catchError() à la fin de la chaîne traite toute erreur survenue à n’importe quelle étape. Cela rend le code asynchrone linéaire et lisible.

CompletableFuture en Java

En Java, CompletableFuture étend le concept Future/Promise. La méthode supplyAsync() lance une tâche asynchrone dans ForkJoinPool.commonPool(). thenApply() transforme le résultat, thenCompose() déballe un CompletableFuture imbriqué. exceptionally() traite une erreur en retournant une valeur par défaut. allOf() et anyOf() fonctionnent comme Promise.all et Promise.race en JavaScript. CompletableFuture prend en charge l’achèvement manuel via complete() et completeExceptionally() — c’est analogue à Promise resolve/reject.

Promise et le contrat d’asynchronie

Promise est un contrat avec l’un des trois états : pending (en attente), fulfilled (tenue) ou rejected (rejetée). Une fois passé à fulfilled ou rejected, la Promise ne change jamais — cela garantit l’immuabilité du résultat pour tous les consommateurs. La méthode .then() est appelée de manière asynchrone après être passé à un état terminé.

Promise.all attend que toutes les promesses passées soient terminées et retourne un tableau de résultats dans le même ordre. Si une promesse échoue avec une erreur — tout Promise.all passe à rejected. Promise.race retourne le résultat de la première promesse terminée (succès ou erreur). Promise.allSettled attend toutes les promesses indépendamment des erreurs — retourne l’état de chacune.

Le chaînage est l’avantage clé de Promise par rapport aux callbacks. Chaque .then() retourne une nouvelle Promise, permettant des chaînes de longueur arbitraire. Une erreur à n’importe quel maillon de la chaîne se propage jusqu’au .catch() le plus proche. La méthode finally() exécute du code après la fin de la chaîne indépendamment du résultat — pour le nettoyage des ressources.

Exemples de code Future (Dart)

Le premier exemple — créer un Future via une fonction async et le traiter avec then/catchError :

dart
Future<String> fetchData() async {
    await Future.delayed(Duration(seconds: 1))
    return "Données chargées"
}

fetchData()
    .then((result) => print(result))
    .catchError((error) => print("Erreur : $error"))

Le deuxième exemple — combiner plusieurs Futures avec Future.wait :

dart
Future<List<String>> loadAll() async {
    final futures = [
        fetchFromApi("/users"),
        fetchFromApi("/posts"),
        fetchFromApi("/comments")
    ]
    final results = await Future.wait(futures)
    return results
}

Le troisième exemple — Promise en JavaScript avec création manuelle et une chaîne then :

js
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("Terminé")
    }, 1000)
})

promise
    .then(value => console.log(value))
    .catch(err => console.error(err))

Future vs autres motifs asynchrones

Future/Promise diffère du style callback en retournant un objet contrat au lieu d’accepter une fonction callback comme argument. Le style callback conduit à l’imbrication (enfer des callbacks), tandis que Future permet de construire des chaînes then() plates. La syntaxe async/await rend le code Future encore plus linéaire, ressemblant à du code synchrone.

Future représente exactement un résultat asynchrone — une émission, après laquelle le Future se termine. Contrairement à Observable (Rx, ReactiveX) ou Flow (Kotlin Coroutines), Future ne prend pas en charge de multiples valeurs dans le temps. Si vous avez besoin d’un flux d’événements — utilisez Stream en Dart, Observable en Rx ou Flow en Kotlin.

CompletableFuture en Java est un analogue de Promise avec une API étendue : supplyAsync, thenApply, thenCompose, exceptionally. CompletableFuture permet de combiner plusieurs opérations asynchrones via allOf, anyOf, et permet également de spécifier un Executor personnalisé pour l’exécution. Scala Future utilise ExecutionContext pour gérer le pool de threads et prend en charge la composition via for-comprehension.

En Dart, le motif Future diffère de Promise en JavaScript par le typage strict de Dart : Future<String> garantit le type de la valeur de retour. Les fonctions async en Dart doivent retourner un Future, et le compilateur vérifie que tous les chemins retournent un type correct. Future.wait est équivalent à Promise.all — il prend Iterable<Future<T>> et retourne Future<List<T>>. Future.delayed et Future.error sont des fabriques pratiques pour tester des scénarios asynchrones.

Future/Promise est implémenté en Python via concurrent.futures.Future et asyncio.Future. concurrent.futures.ThreadPoolExecutor.submit() retourne un Future, sur lequel on peut appeler result() — un appel bloquant. asyncio.Future est un conteneur compatible await pour un résultat asynchrone dans Asyncio. asyncio.gather() exécute plusieurs coroutines en parallèle et retourne une liste de résultats, similaire à Promise.all en JavaScript. Python utilise également asyncio.ensure_future basé sur des callbacks et des chaînes add_done_callback pour composer des opérations asynchrones, mais dans le code moderne, la syntaxe async/await avec asyncio.Task est préférée.

Dans le développement mobile, Future est activement utilisé dans les applications Flutter. Chaque requête réseau du package http ou dio retourne un Future. FutureBuilder est un widget qui prend un Future et un état snapshot : connectionDone, hasData, hasError. Lorsque les données sont reçues, snapshot.data contient le résultat du Future. StreamBuilder est l’analogue pour les valeurs multiples. FutureBuilder élimine la gestion manuelle de l’état de chargement via setState.

Scala Future utilise implicitement ExecutionContext — le pool de threads sur lequel la tâche asynchrone s’exécute. La composition via map, flatMap, filter fonctionne parce que Future est une monade. for-comprehension permet de combiner séquentiellement plusieurs Futures sans imbrication : for { a <- futureA; b <- futureB } yield a + b. Future.sequence fonctionne comme Promise.all. Le repli en cas d’erreur est implémenté via recover et recoverWith.

Future/Promise en C++ est représenté par les classes std::future et std::promise de la bibliothèque <future>. std::async lance une fonction asynchrone et retourne std::future. std::promise permet de définir manuellement une valeur via set_value() ou une erreur via set_exception(). Contrairement à Dart et JavaScript, std::future.get() bloque le thread jusqu’à ce que le résultat soit reçu — c’est une différence importante à considérer lors de la conception d’applications C++ multithread.

Motifs Future

Lors de la conception d’API retournant des Futures, suivez la règle de la source unique de vérité : chaque requête asynchrone est créée une fois et mise en cache via Future.memoize. Si deux composants demandent les mêmes données, ils reçoivent le même Future — cela évite les requêtes en double. Pour le timeout, utilisez Future.timeout (Dart) ou Promise.race avec un timeout pour garantir que l’opération asynchrone se termine dans un intervalle donné.

Le motif Retry dans Future est implémenté via une chaîne récursive : en cas d’erreur dans catch, la même fonction asynchrone est appelée avec un délai. L’exponential backoff augmente l’intervalle entre les tentatives : 1 s — 2 s — 4 s — jusqu’à 30 s max. En Dart, cela est encapsulé dans une extension sur Future : future.retry(maxRetries : 3, delay : Duration(seconds : 1)). En Scala, Future.zip combine deux résultats indépendants en un tuple — une alternative à Promise.all pour deux Futures. L’annulation n’est pas prise en charge dans les Futures standard, mais est implémentée via CancellationToken ou AbortController en JavaScript.

Questions fréquentes

Quelle est la différence entre Future et Promise ?

Future est un conteneur en lecture seule pour lire un résultat asynchrone via then ou await. Promise est un contrat en écriture seule qui accepte une valeur via resolve() et la lie au Future. En Dart et JavaScript, ces concepts sont combinés : Future/Promise est une classe. En Java et Scala, ils sont séparés.

Quelle est la différence entre Future et Observable ?

Future représente un seul résultat asynchrone — il émet exactement une valeur et se termine. Observable (Rx) émet plusieurs valeurs dans le temps — c’est un flux asynchrone. Si vous avez besoin d’une réponse HTTP — utilisez Future. Si vous avez besoin d’un flux de modifications de base de données — utilisez Observable ou Stream.

Qu’est-ce que async/await et quel est son lien avec Future ?

async/await est un sucre syntaxique au-dessus de Future/Promise. Le mot-clé async marque une fonction comme asynchrone — elle retourne un Future. await suspend l’exécution jusqu’à ce que le Future soit terminé, sans bloquer le thread. En Dart, JavaScript, Python et C#, async/await a remplacé les chaînes then dans la plupart des scénarios.

Comment gérer les erreurs dans une chaîne Future ?

En Dart, utilisez .catchError() à la fin de la chaîne — il attrape les exceptions à n’importe quelle étape. En JavaScript — .catch(). Dart dispose également de try/await/catch dans les fonctions async. Pour la récupération d’erreur, utilisez .catchError() avec une valeur par défaut ou un nouveau Future.

Qu’est-ce que Promise.all et quand l’utiliser ?

Promise.all prend un tableau de promesses et retourne une seule Promise qui se résout avec un tableau de résultats. Toutes les promesses sont exécutées en parallèle — cela accélère les opérations indépendantes (par exemple, charger plusieurs fichiers). Si une promesse est rejetée — tout Promise.all est rejeté avec la même erreur.

Résumé

  • Future/Promise — un motif de programmation asynchrone avec un contrat pour une valeur unique
  • Future — un conteneur en lecture seule pour lire le résultat d’une opération
  • Promise — un contrat en écriture seule qui remplit le Future via resolve/reject
  • Chaînes then — traitement plat d’étapes asynchrones sans enfer des callbacks
  • async/await — sucre syntaxique sur Future, rendant le code linéaire
  • Promise.all — exécution parallèle de plusieurs opérations asynchrones
  • Pour des valeurs multiples dans le temps, utilisez Stream ou Observable, pas Future

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