onComplete和flatMap在Future中有什么区别?

22
我是一个有用的助手,可以为您翻译文本。

我正在使用ReactiveMongo驱动程序编写Scala应用程序。访问数据库的方法始终返回Future[T]。以下代码片段等效吗?

(使用onComplete

val results: Future[List[Tag]] = Tags.all.toList
results onComplete {
    case Success(list) => //do something with list
    case Failure(t) => //throw the error
}

(使用flatMap

Tags.all.toList.flatMap(list => //do something with list)

有什么区别?

flatMap不会抛出错误?而且flatMap是像onComplete这样的回调,还是等到Tags.all.toList语句完成才执行?


从签名中可以看出:同样地,尝试使用单子(Monad),flatMap 不关心失败。这就是单子的作用:你将任何错误传递下去,并且只有在管道中没有错误时才应用操作。最后,你需要捕获错误和成功。 - Little Alien
1个回答

45

当迷茫不清时,请遵循类型。

onComplete 返回Unit,它允许您对Future的结果进行操作,但不会返回值

flatMap 允许您对列表进行某些操作并且返回新的Future

因此,flatMap 更加强大,因为它允许您链接多个 futures,在途中处理其值,并仅在最后处理失败情况。用 Erik Meijer 的话来说,“它可以引导您走上愉快的道路”。

例如,您可以执行以下操作

val finalFuture = results
 .flatMap(x => /* do something and return a future */)
 .flatMap(y => /* do something else and return a future */)
 .flatMap(z => /* do something else and return a future */)
 .map(myresult => /* do something */)

如果在途中出现问题,链条会被及早打破,并显示第一个错误。

这样可以实现更加简洁的语法。

 val finalFuture = for {
    x <- results
    y <- /* do something and return a future */
    z <- /* do something and return a future */
 } yield something(z)

如果您需要处理失败情况,现在可以使用onComplete,或者更好的方法是简单地返回Future,因为它已经包含有关异步计算是否成功的信息。


在这个例子中,finalFuture无论something(z)的类型是什么,都会返回一个Future[Nothing]。如果您需要将something(z): T传递给期望T的函数怎么办? - Azeli
@Azeli 最终的 finalFuture 类型取决于 something 的返回类型。如果 something 返回 A,则 finalFuture 为 Future[A]。如果需要将类型为 A 的值传递给函数,必须在 Future 上下文中进行,即使用 for-comprehension 或直接使用 map。或者,您可以阻塞 future 并等待其结果,但这通常不是一个好策略。 - Gabriele Petronella

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接