未来和承诺的区别是什么? 它们都像未来结果的占位符,但主要的区别在哪里?
当前回答
不确定这是否能成为一个答案,但正如我看到其他人对某人说的那样,看起来你需要对这两个概念进行两个单独的抽象,这样其中一个(未来)只是另一个(承诺)的只读视图……但实际上这是不需要的。
例如,看看在javascript中承诺是如何定义的:
https://promisesaplus.com/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
重点是使用then方法的可组合性,如:
asyncOp1()
.then(function(op1Result){
// do something
return asyncOp2();
})
.then(function(op2Result){
// do something more
return asyncOp3();
})
.then(function(op3Result){
// do something even more
return syncOp4(op3Result);
})
...
.then(function(result){
console.log(result);
})
.catch(function(error){
console.log(error);
})
这使得异步计算看起来像同步:
try {
op1Result = syncOp1();
// do something
op1Result = syncOp2();
// do something more
op3Result = syncOp3();
// do something even more
syncOp4(op3Result);
...
console.log(result);
} catch(error) {
console.log(error);
}
这很酷。 (没有async-await那么酷,但async-await只是删除了样板文件....然后(function(result) {....从它)。
实际上它们的抽象作为承诺构造函数很好
new Promise( function(resolve, reject) { /* do it */ } );
允许你提供两个回调,它们可以用来成功完成Promise,也可以用来报错。因此,只有构造Promise的代码才能完成它,而接收已构造的Promise对象的代码具有只读视图。
通过继承,如果解析和拒绝是受保护的方法,则可以实现上述目标。
其他回答
(到目前为止,我对答案不是很满意,所以这里是我的尝试…)
我认为凯文·赖特的评论
你可以做出一个承诺,它是由你来遵守它。当别人向你许下承诺时,你必须等着看他们将来是否遵守
总结得很好,但一些解释可能是有用的。
未来和承诺是非常相似的概念,不同的是未来是一个只读容器,用于存放还不存在的结果,而承诺可以写入(通常只能写入一次)。Java 8的CompletableFuture和Guava的SettableFuture可以被认为是承诺,因为它们的值可以设置(“完成”),但它们也实现了Future接口,因此对客户端来说没有区别。
未来的结果将由“其他人”设定——通过异步计算的结果。注意FutureTask -一个经典的future -必须用Callable或Runnable初始化,没有无参数构造函数,而且future和FutureTask从外部看都是只读的(FutureTask的set方法是受保护的)。该值将从内部设置为计算的结果。
另一方面,promise的结果可以由“you”(实际上是任何人)随时设置,因为它有一个公共setter方法。CompletableFuture和SettableFuture都可以在没有任何任务的情况下创建,它们的值可以在任何时候设置。您向客户端代码发送一个承诺,并在稍后按照您的意愿实现它。
注意,CompletableFuture不是一个“纯粹的”承诺,它可以像FutureTask一样用任务初始化,它最有用的特性是处理步骤的不相关链接。
还要注意,promise不一定是future的子类型,也不一定是同一个对象。在Scala中,Future对象是由异步计算或不同的Promise对象创建的。在c++中,情况类似:承诺对象由生产者使用,而未来对象由消费者使用。这种分离的好处是客户端不能设置将来的值。
Spring和EJB 3.1都有一个AsyncResult类,它类似于Scala/ c++的承诺。AsyncResult确实实现了Future,但这不是真正的Future: Spring/EJB中的异步方法通过一些后台魔法返回一个不同的只读Future对象,而这个“真正的”Future可以被客户端用来访问结果。
我知道已经有了一个公认的答案,但我仍然想补充我的意见:
TLDR:未来和承诺是异步操作的两个方面:消费者/调用者vs.生产者/实现者。
作为异步API方法的调用者,您将获得一个Future作为计算结果的句柄。例如,你可以对它调用get()来等待计算完成并检索结果。
现在想想这个API方法实际上是如何实现的:实现者必须立即返回一个Future。它们负责在计算完成后立即完成该future(它们将知道这一点,因为它正在实现分派逻辑;-))。它们将使用Promise/CompletableFuture来完成:立即构造并返回CompletableFuture,并在计算完成后调用complete(T result)。
对于客户端代码,Promise用于在结果可用时观察或附加回调,而Future用于等待结果然后继续。从理论上讲,任何可以用未来完成的事情都可以用承诺完成,但由于风格的差异,不同语言的承诺的最终API使得链接更容易。
在这个例子中,您可以看看如何在Java中使用Promises 用于创建异步调用序列:
doSomeProcess()
.whenResult(result -> System.out.println(String.format("Result of some process is '%s'", result)))
.whenException(e -> System.out.println(String.format("Exception after some process is '%s'", e.getMessage())))
.map(String::toLowerCase)
.mapEx((result, e) -> e == null ? String.format("The mapped result is '%s'", result) : e.getMessage())
.whenResult(s -> System.out.println(s));
Future接口中没有set方法,只有get方法,所以是只读的。 关于CompletableFuture,这篇文章可能会有帮助。 completablefuture
推荐文章
- 到底是什么导致了堆栈溢出错误?
- 为什么Android工作室说“等待调试器”如果我不调试?
- Java:路径vs文件
- ExecutorService,如何等待所有任务完成
- Maven依赖Servlet 3.0 API?
- 如何在IntelliJ IDEA中添加目录到应用程序运行概要文件中的类路径?
- getter和setter是糟糕的设计吗?相互矛盾的建议
- Android room persistent: AppDatabase_Impl不存在
- Java的String[]在Kotlin中等价于什么?
- Intellij IDEA上的System.out.println()快捷方式
- 使用Spring RestTemplate获取JSON对象列表
- Spring JPA选择特定的列
- URLEncoder不能翻译空格字符
- Java中的super()
- 如何转换JSON字符串映射<字符串,字符串>与杰克逊JSON