如何承诺。与Scala futures达成一致?

如何承诺。与Scala futures达成一致?,scala,promise,future,Scala,Promise,Future,我有两个scala期货。我想在两个都完成后执行一个操作,无论它们是否成功完成。(此外,我希望当时能够检查这些结果。) 在Javascript中,这是 Scala是否提供了一种简单的方法来实现这一点 最后一个问题,如果有关系的话:我想在JRuby应用程序中这样做。您可以使用该方法创建一个始终成功的未来,并将结果或错误作为Try对象返回 def toTry[A](future:future[A])(隐式ec:ExecutionContext):future[Try[A]]= future.trans

我有两个scala期货。我想在两个都完成后执行一个操作,无论它们是否成功完成。(此外,我希望当时能够检查这些结果。)

在Javascript中,这是

Scala是否提供了一种简单的方法来实现这一点

最后一个问题,如果有关系的话:我想在JRuby应用程序中这样做。

您可以使用该方法创建一个始终成功的未来,并将结果或错误作为
Try
对象返回

def toTry[A](future:future[A])(隐式ec:ExecutionContext):future[Try[A]]=
future.transform(x=>Success(x))
要将两个期货组合成一个期货,您可以使用
zip

def结算2[A,B](fa:Future[A],fb:Future[B])(隐式ec:ExecutionContext)
:Future[(Try[A],Try[B])]=
托特里(足总)。拉链(托特里(足总)
如果您想以这种方式组合任意数量的期货,可以使用
Future.traverse

def allSettled[A](期货:列表[Future[A]])(隐式ec:ExecutionContext)
:Future[列表[尝试[A]]=
期货交易(期货)(总计)

通常在这种情况下,我们使用
Future.sequence
将一个未来集合转换为一个未来,这样您就可以映射到它,但Scala会将失败的未来短路,并且不会在这之后等待任何东西(Scala认为一个失败就是所有失败),这不适合您的情况

在这种情况下,您需要将失败的映射为成功,然后按顺序执行,例如

val settledFuture = Future.sequence(List(future1, future2, ...).map(_.recoverWith { case _ => Future.unit }))
settledFuture.map(//Here it is all settled)
编辑

由于需要保留结果,而不是映射到Future.unit,我们将实际结果映射到Try的另一层:

val settledFuture = Future.sequence(
  List(Future(1), Future(throw new Exception))
    .map(_.map(Success(_)).recover(Failure(_)))
  )
settledFuture.map(println(_))
//Output: List(Success(1), Failure(java.lang.Exception))
EDIT2

它可以通过
转换进一步简化:

Future.sequence(listOfFutures.map(_.transform(Success(_))))

也许您可以使用一个并发计数器来跟踪已完成的
Future
s的数量,然后在所有
Future
s完成后完成
Promise

def allSettled[T](futures: List[Future[T]]): Future[List[Future[T]]] = {
  val p = Promise[List[Future[T]]]()
  val length = futures.length
  val completedCount = new AtomicInteger(0)
  futures foreach {
    _.onComplete { _ =>
      if (completedCount.incrementAndGet == length) p.trySuccess(futures)
    }
  }
  p.future
}

val futures = List(
  Future(-11),
  Future(throw new Exception("boom")),
  Future(42)
)

allSettled(futures).andThen(println(_))
// Success(List(Future(Success(-11)), Future(Failure(java.lang.Exception: boom)), Future(Success(42))))

你有没有考虑过未来的顺序?这是一个糟糕的解决方案。如果你这样做的话,你会失去一个例外,这个例外可能会在以后发生。你通常会得到一个类型为
Any
的结果,因为这通常是期货的结果类型和
单位的最小上限,如果期货返回单位,你不知道最初的期货是成功还是失败。最重要的是,OP提到他有两个期货,没有理由假设它们是同一类型的,所以你再次失去了类型安全性。此外,
Future.sequence(foo.map(bar))
更好地表达为
Future.traverse(foo)(bar)
@MatthiasBerndt添加了保持结果的解决方案a)丢失结果类型,b)在一般情况下不知道未来是成功还是失败c)拥有
Future.sequence(foo.map(bar))
antipattern和d)不能在保留不同类型的未来的同时组合它们的类型(OP明确询问了两个未来,而不是任意数字)@MatthiasBerndt可丢弃结果的成功是非常反模式的。同样,OP没有提到他的未来应该持续的结果类型。我们可以在Scala中进行模式匹配以匹配类型。在他对JS
Promise.allsolited
的引用中,它返回一个所有结果的集合,这正是我的示例所做的。是否使用
Throwable
的子类型作为
Future
的成功结果是一个反模式并不重要;像这样的通用代码不应该对此做出任何假设。非密封类型(如
Any
)上的模式匹配是另一个糟糕的想法,因为编译器无法检查穷尽性,也因为它不能处理泛型(例如,不能区分
List[Int]
List[String]
)。堆叠
Future
Try
太复杂了,这只是一个愚蠢的论点,因为
Promise.allSettled
生成了一个与Scala的
Try
类型同构的对象数组。我所写的
allsolided
方法与您在惯用Scala中使用JavaScript的
Promise.allsolided
非常接近。