Future/Promise es un patrón de programación asíncrona que representa un contenedor para el resultado de una operación aún no completada. Según Dart Documentation, 2025, Future es un resultado de solo lectura de cómputos diferidos, Promise es un contrato de solo escritura que llena este resultado. Future se usa en Dart, Java, Scala y C++ para cadenas then/catch.
Puntos clave
Future/Promise es un par de objetos interconectados que dividen un resultado asíncrono en dos roles. Promise puede escribir el resultado (resolve) o un error (reject). Future solo puede leerlo — a través de callbacks (then, catchError) o mediante await. Esta separación garantiza que el consumidor no pueda cambiar el resultado, solo usarlo.
El lenguaje Dart usa Future como su principal mecanismo asíncrono. Future<T> es un contrato para recibir un valor de tipo T en el futuro. Un Future puede estar en uno de tres estados: unresolved (operación en curso), resolved with value (completado exitosamente) o resolved with error (completado con error). Una vez que pasa a un estado resuelto, el Future nunca cambia.
Promise en JavaScript es análogo al Future de Dart, pero con una API más rica. Promise toma un ejecutor — una función con parámetros resolve y reject. Los métodos estáticos Promise.all, Promise.race, Promise.allSettled permiten combinar múltiples promesas. Las aplicaciones modernas usan la sintaxis async/await sobre Promise.
Future funciona basado en un event loop — un ciclo de eventos que procesa operaciones asíncronas sin bloquear el hilo principal. Cuando se llama a una función asíncrona (por ejemplo, http.get), devuelve inmediatamente un Future. La solicitud real se ejecuta en segundo plano, mientras el event loop continúa procesando otros eventos. Después de que la operación se completa, el Future pasa a un estado resuelto y se llama a then.
Event loop es el mecanismo clave sobre el que se construyen Dart y JavaScript. El event loop mantiene dos colas: la cola de microtareas (tareas cortas, ejecutadas antes del siguiente evento) y la cola de eventos (eventos IO, temporizadores). Future.then coloca un callback en la cola de microtareas, Future.microtask — ejecución prioritaria antes del siguiente frame.
Las cadenas de then() permiten procesar secuencialmente los resultados de operaciones asíncronas sin callback hell. Cada then() recibe el resultado del paso anterior y devuelve un nuevo Future. catchError() al final de la cadena maneja cualquier error que haya ocurrido en cualquier paso. Esto hace que el código asíncrono sea lineal y legible.
En Java, CompletableFuture extiende el concepto Future/Promise. El método supplyAsync() lanza una tarea asíncrona en ForkJoinPool.commonPool(). thenApply() transforma el resultado, thenCompose() desempaqueta un CompletableFuture anidado. exceptionally() maneja un error devolviendo un valor por defecto. allOf() y anyOf() funcionan como Promise.all y Promise.race en JavaScript. CompletableFuture admite la finalización manual mediante complete() y completeExceptionally() — esto es análogo a Promise resolve/reject.
Promise es un contrato con uno de tres estados: pending (pendiente), fulfilled (cumplido) o rejected (rechazado). Una vez que pasa a fulfilled o rejected, el Promise nunca cambia — esto garantiza la inmutabilidad del resultado para todos los consumidores. El método .then() se llama asíncronamente después de pasar a cualquier estado completado.
Promise.all espera a que todas las promesas pasadas se completen y devuelve un array de resultados en el mismo orden. Si una promesa falla con un error — todo Promise.all pasa a rejected. Promise.race devuelve el resultado de la primera promesa completada (éxito o error). Promise.allSettled espera a todas las promesas independientemente de los errores — devuelve el estado de cada una.
Chaining es la ventaja clave de Promise sobre los callbacks. Cada .then() devuelve un nuevo Promise, permitiendo cadenas de longitud arbitraria. Un error en cualquier eslabón de la cadena se propaga hasta el .catch() más cercano. El método finally() ejecuta código después de que la cadena se completa independientemente del resultado — para limpieza de recursos.
El primer ejemplo — crear un Future mediante una función async y manejarlo con then/catchError:
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 1))
return "Datos cargados"
}
fetchData()
.then((result) => print(result))
.catchError((error) => print("Error: $error"))
El segundo ejemplo — combinar múltiples Futures con Future.wait:
Future<List<String>> loadAll() async {
final futures = [
fetchFromApi("/users"),
fetchFromApi("/posts"),
fetchFromApi("/comments")
]
final results = await Future.wait(futures)
return results
}
El tercer ejemplo — Promise en JavaScript con creación manual y una cadena then:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hecho")
}, 1000)
})
promise
.then(value => console.log(value))
.catch(err => console.error(err))
Future/Promise se diferencia del estilo callback por devolver un objeto contrato en lugar de aceptar una función callback como argumento. El estilo callback conduce al anidamiento (callback hell), mientras que Future permite construir cadenas then() planas. La sintaxis async/await hace que el código Future sea aún más lineal, asemejándose al código síncrono.
Future representa exactamente un resultado asíncrono — una emisión, después de la cual el Future se completa. A diferencia de Observable (Rx, ReactiveX) o Flow (Kotlin Coroutines), Future no admite múltiples valores en el tiempo. Si necesitas un flujo de eventos — usa Stream en Dart, Observable en Rx o Flow en Kotlin.
CompletableFuture en Java es un análogo de Promise con una API extendida: supplyAsync, thenApply, thenCompose, exceptionally. CompletableFuture permite combinar múltiples operaciones asíncronas mediante allOf, anyOf, y también permite especificar un Executor personalizado para la ejecución. Scala Future usa ExecutionContext para gestionar el pool de hilos y admite la composición mediante for-comprehension.
En Dart, el patrón Future se diferencia de Promise de JavaScript en que Dart tiene tipado estricto: Future<String> garantiza el tipo del valor devuelto. Las funciones async en Dart deben devolver un Future, y el compilador verifica que todas las rutas devuelvan un tipo correcto. Future.wait es equivalente a Promise.all — toma Iterable<Future<T>> y devuelve Future<List<T>>. Future.delayed y Future.error son fábricas convenientes para probar escenarios asíncronos.
Future/Promise está implementado en Python mediante concurrent.futures.Future y asyncio.Future. concurrent.futures.ThreadPoolExecutor.submit() devuelve un Future, en el que se puede llamar a result() — una llamada bloqueante. asyncio.Future es un contenedor compatible con await para un resultado asíncrono en Asyncio. asyncio.gather() ejecuta múltiples corutinas en paralelo y devuelve una lista de resultados, similar a Promise.all en JavaScript. Python también usa asyncio.ensure_future basado en callbacks y cadenas add_done_callback para componer operaciones asíncronas, pero en el código moderno se prefiere la sintaxis async/await con asyncio.Task.
En el desarrollo móvil, Future se usa activamente en aplicaciones Flutter. Cada solicitud de red del paquete http o dio devuelve un Future. FutureBuilder es un widget que toma un Future y un estado de snapshot: connectionDone, hasData, hasError. Cuando se reciben datos, snapshot.data contiene el resultado del Future. StreamBuilder es el análogo para múltiples valores. FutureBuilder elimina la gestión manual del estado de carga mediante setState.
Scala Future usa ExecutionContext implícitamente — el pool de hilos en el que se ejecuta la tarea asíncrona. La composición mediante map, flatMap, filter funciona porque Future es una mónada. for-comprehension permite combinar secuencialmente múltiples Futures sin anidamiento: for { a <- futureA; b <- futureB } yield a + b. Future.sequence funciona como Promise.all. La recuperación de errores se implementa mediante recover y recoverWith.
Future/Promise en C++ está representado por las clases std::future y std::promise de la biblioteca <future>. std::async lanza una función asíncrona y devuelve std::future. std::promise permite establecer manualmente un valor mediante set_value() o un error mediante set_exception(). A diferencia de Dart y JavaScript, std::future.get() bloquea el hilo hasta que se recibe el resultado — esta es una diferencia importante a considerar al diseñar aplicaciones C++ multihilo.
Al diseñar APIs que devuelven Futures, sigue la regla de la fuente única de verdad: cada solicitud asíncrona se crea una vez y se almacena en caché mediante Future.memoize. Si dos componentes solicitan los mismos datos, reciben el mismo Future — esto evita solicitudes duplicadas. Para timeout, usa Future.timeout (Dart) o Promise.race con un timeout para garantizar que la operación asíncrona se complete dentro de un intervalo dado.
El patrón Retry en Future se implementa mediante una cadena recursiva: al error en catch, se llama a la misma función asíncrona con un retardo. Exponential backoff aumenta el intervalo entre intentos: 1 seg — 2 seg — 4 seg — hasta max 30 seg. En Dart esto se encapsula en una extensión de Future: future.retry(maxRetries: 3, delay: Duration(seconds: 1)). En Scala, Future.zip combina dos resultados independientes en una tupla — una alternativa a Promise.all para dos Futures. La cancelación no es compatible con los Futures estándar, pero se implementa mediante CancellationToken o AbortController en JavaScript.
Preguntas frecuentes
Future es un contenedor de solo lectura para leer un resultado asíncrono mediante then o await. Promise es un contrato de solo escritura que acepta un valor mediante resolve() y lo vincula al Future. En Dart y JavaScript, estos conceptos están combinados: Future/Promise es una clase. En Java y Scala están separados.
Future representa un único resultado asíncrono — emite exactamente un valor y se completa. Observable (Rx) emite múltiples valores en el tiempo — es un flujo asíncrono. Si necesitas una respuesta HTTP — usa Future. Si necesitas un flujo de cambios de base de datos — usa Observable o Stream.
async/await es azúcar sintáctico sobre Future/Promise. La palabra clave async marca una función como asíncrona — devuelve un Future. await pausa la ejecución hasta que el Future se complete, sin bloquear el hilo. En Dart, JavaScript, Python y C#, async/await ha reemplazado las cadenas then en la mayoría de los escenarios.
En Dart, usa .catchError() al final de la cadena — captura excepciones en cualquier etapa. En JavaScript — .catch(). Dart también tiene try/await/catch dentro de funciones async. Para la recuperación de errores, usa .catchError() con un valor por defecto o un nuevo Future.
Promise.all toma un array de promesas y devuelve una única Promise que se resuelve con un array de resultados. Todas las promesas se ejecutan en paralelo — esto acelera operaciones independientes (por ejemplo, cargar múltiples archivos). Si alguna promesa es rechazada — todo Promise.all es rechazado con el mismo error.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también