Future/Promise 是一种异步编程模式,代表尚未完成操作的结果容器。根据 Dart Documentation, 2025,Future 是延迟计算的只读结果,Promise 是填充此结果的只写合约。 Future 在 Dart、Java、Scala 和 C++ 中用于 then/catch 链。
要点
Future/Promise 是一对相互关联的对象,将异步结果分为两个角色。Promise 可以写入结果(resolve)或错误(reject)。Future 只能读取它 — 通过回调(then、catchError)或通过 await。这种划分确保消费者不能修改结果,只能使用它。
Dart 语言使用 Future 作为主要的异步机制。Future<T> 是将来接收 T 类型值的合约。Future 可以处于三种状态之一:unresolved(操作正在执行)、resolved with value(成功完成)或 resolved with error(以错误完成)。进入 resolved 状态后,Future 不会改变。
JavaScript 中的 Promise 类似于 Dart 的 Future,但具有更丰富的 API。Promise 接受一个执行器(executor)——一个带有 resolve 和 reject 参数的函数。静态方法 Promise.all、Promise.race、Promise.allSettled 允许组合多个 promise。现代应用程序使用基于 Promise 的 async/await 语法。
Future 基于事件循环(event loop)工作——事件循环在不阻塞主线程的情况下处理异步操作。当调用异步函数(例如 http.get)时,它会立即返回一个 Future。实际请求在后台执行,而事件循环继续处理其他事件。操作完成后,Future 进入 resolved 状态并调用 then。
事件循环(Event loop) 是 Dart 和 JavaScript 构建的关键机制。事件循环维护两个队列:微任务队列(microtask queue,在下一次事件之前执行的短任务)和事件队列(event queue,IO 事件、定时器)。Future.then 将回调放入微任务队列,Future.microtask —— 在下一帧之前优先执行。
then() 链允许在没有回调地狱的情况下顺序处理异步操作的结果。每个 then() 接收前一步的结果并返回一个新的 Future。链末尾的 catchError() 处理任何步骤中出现的任何错误。这使得异步代码线性且可读。
在 Java 中,CompletableFuture 扩展了 Future/Promise 的概念。supplyAsync() 方法在 ForkJoinPool.commonPool() 中启动异步任务。thenApply() 转换结果,thenCompose() —— 展开嵌套的 CompletableFuture。exceptionally() 通过返回默认值来处理错误。allOf() 和 anyOf() 类似于 JavaScript 中的 Promise.all 和 Promise.race。CompletableFuture 支持通过 complete() 和 completeExceptionally() 手动完成——这是 Promise resolve/reject 的类似物。
Promise 是一个具有三种状态之一的合约:pending(等待)、fulfilled(成功完成)或 rejected(以错误完成)。进入 fulfilled 或 rejected 状态后,Promise 永远不会改变——这保证了所有消费者结果的不变性。.then() 方法在进入任何已完成状态后异步调用。
Promise.all 等待所有传递的 promise 完成,并返回相同顺序的结果数组。如果一个 promise 以错误结束——整个 Promise.all 进入 rejected。Promise.race 返回第一个完成的 promise 的结果(成功或错误)。Promise.allSettled 等待所有 promise,无论错误如何——返回每个的状态。
链式调用(Chaining) —— Promise 相对于回调的主要优势。每个 .then() 返回一个新的 Promise,允许构建任意长度的链。链中任何环节的错误都会传播到最近的 .catch()。finally() 方法在链完成后无论结果如何都执行代码——用于清理资源。
第一个示例——通过 async 函数创建 Future 并通过 then/catchError 处理:
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 1))
return "数据已加载"
}
fetchData()
.then((result) => print(result))
.catchError((error) => print("错误:$error"))
第二个示例——通过 Future.wait 组合多个 Future:
Future<List<String>> loadAll() async {
final futures = [
fetchFromApi("/users"),
fetchFromApi("/posts"),
fetchFromApi("/comments")
]
final results = await Future.wait(futures)
return results
}
第三个示例——JavaScript 中的 Promise,手动创建和 then 链:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("完成")
}, 1000)
})
promise
.then(value => console.log(value))
.catch(err => console.error(err))
Future/Promise 与回调风格的不同之处在于,它返回一个对象合约,而不是接受回调函数作为参数。回调风格导致嵌套(回调地狱),而 Future 允许构建扁平的 then() 链。async/await 语法使使用 Future 的代码更加线性,类似于同步代码。
Future 恰好代表一个异步结果——一次发射,之后 Future 结束。与 Observable(Rx、ReactiveX)或 Flow(Kotlin Coroutines)不同,Future 不支持随时间变化的多个值。如果您需要事件流——请在 Dart 中使用 Stream,在 Rx 中使用 Observable,或在 Kotlin 中使用 Flow。
Java 中的 CompletableFuture —— Promise 的类似物,具有扩展 API:supplyAsync、thenApply、thenCompose、exceptionally。CompletableFuture 允许通过 allOf、anyOf 组合多个异步操作,以及设置自己的执行器(Executor)执行。Scala Future 使用 ExecutionContext 管理线程池,并通过 for-comprehension 支持组合。
在 Dart 中,Future 模式与 JavaScript Promise 的不同之处在于 Dart 具有严格的类型化:Future<String> 保证了返回值的类型。Dart 中的 async 函数必须返回 Future,编译器会检查所有路径是否返回正确的类型。Future.wait 等同于 Promise.all——接受 Iterable<Future<T>> 并返回 Future<List<T>>。Future.delayed 和 Future.error 是测试异步场景的便捷工厂方法。
Future/Promise 在 Python 中通过 concurrent.futures.Future 和 asyncio.Future 实现。concurrent.futures.ThreadPoolExecutor.submit() 返回一个 Future,可以调用 result() —— 阻塞调用。asyncio.Future 是 Asyncio 中用于异步结果的与 await 兼容的容器。asyncio.gather() 并行运行多个协程并返回结果列表,类似于 JavaScript 中的 Promise.all。Python 也使用基于回调的 asyncio.ensure_future 和 add_done_callback 链进行异步操作组合,但在现代代码中首选使用 asyncio.Task 的 async/await 语法。
在移动开发中,Future 在 Flutter 应用程序中被积极使用。来自 http 或 dio 包的每个网络请求都返回一个 Future。FutureBuilder —— 一个接受 Future 和状态快照的小部件:connectionDone、hasData、hasError。接收数据后,snapshot.data 包含 Future 的结果。StreamBuilder —— 多个值的类似物。FutureBuilder 消除了通过 setState 手动管理加载状态。
Scala Future 隐式使用 ExecutionContext —— 执行异步任务的线程池。通过 map、flatMap、filter 的组合之所以有效,是因为 Future 是一个单子。for-comprehension 允许在没有嵌套的情况下顺序组合多个 Future:for { a <- futureA; b <- futureB } yield a + b。Future.sequence 类似于 Promise.all。错误时的回退通过 recover 和 recoverWith 实现。
C++ 中的 Future/Promise 由库 <future> 中的 std::future 和 std::promise 类表示。std::async 启动一个异步函数并返回 std::future。std::promise 允许通过 set_value() 手动设置值或通过 set_exception() 设置错误。与 Dart 和 JavaScript 不同,std::future.get() 会阻塞线程直到收到结果——这是在 C++ 中设计多线程应用程序时需要考虑的一个重要区别。
在设计返回 Future 的 API 时,遵循单一事实来源规则:每个异步请求创建一次,并通过 Future.memoize 缓存。如果两个组件请求相同的数据,它们会得到相同的 Future——这可以防止重复请求。对于超时,请使用 Future.timeout(Dart)或带有超时的 Promise.race,以确保异步操作在指定时间间隔内完成。
Future 中的重试模式通过递归链实现:在 catch 中出错时,以延迟方式调用相同的异步函数。指数退避增加尝试之间的间隔:1 秒 — 2 秒 — 4 秒 — 直到最大 30 秒。在 Dart 中,这封装在 Future 的扩展中:future.retry(maxRetries: 3, delay: Duration(seconds: 1))。在 Scala 中,Future.zip 将两个独立的结果组合成一个元组——对于两个 Future 来说是 Promise.all 的替代方案。标准 Future 不支持取消,但通过 JavaScript 中的 CancellationToken 或 AbortController 实现。
常见问题
Future 是通过 then 或 await 读取异步结果的只读容器。Promise 是只写合约,通过 resolve() 接收值并将其与 Future 关联。在 Dart 和 JavaScript 中,这些概念是统一的:Future/Promise 是一个类。在 Java 和 Scala 中,它们是分开的。
Future 代表单个异步结果——它只发射一个值并结束。Observable(Rx)随时间发射多个值——这是一个异步流。如果您需要一个 HTTP 响应——请使用 Future。如果您需要数据库更改流——请使用 Observable 或 Stream。
async/await 是 Future/Promise 之上的语法糖。关键字 async 将函数标记为异步——它返回一个 Future。await 暂停执行直到 Future 完成,而不阻塞线程。在 Dart、JavaScript、Python 和 C# 中,async/await 在大多数场景中已经取代了 then 链。
在 Dart 中,在链的末尾使用 .catchError() —— 它捕获任何阶段的异常。在 JavaScript 中 —— .catch()。在 Dart 中,在 async 函数内部也可用 try/await/catch。要在错误后恢复,请使用 .catchError() 返回默认值或新的 Future。
Promise.all 接受一个 promise 数组,并返回一个 Promise,该 Promise 将解析为结果数组。所有 promise 并行启动——这加速了独立操作的执行(例如,加载多个文件)。如果任何一个 promise 被拒绝——整个 Promise.all 将被同一错误拒绝。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。