我试图使用scalaz Task进行异步调用。
由于某些奇怪的原因,每当我尝试调用methodA时,虽然我得到一个scalaz.concurrent.Task返回但我从未看到第二个print语句让我相信永远不会返回异步调用。为了让我开始这项任务,是否有一些我不想要的东西?
for {
foo <- println("we are in this for loop!").asAsyncSuccess()
authenticatedUser <- methodA(parameterA)
foo2 <- println("we are out of this this call!").asAsyncSuccess()
} yield {
authenticatedUser
}
def methodA(parameterA: SomeType): Task[User]
答案 0 :(得分:0)
首先,Scalaz Task
很懒:当你创建它或从某种方法获取它时它不会启动。它是设计使得Task
能够很好地结合起来。在您将整个程序完全组合到单个主Task
之前,它无意启动,所以当您完成后,您需要使用Task
方法之一手动启动聚合的perform
,就像unsafePerformSync
那样等待当前线程上聚合异步计算的结果:
(for {
foo <- println("we are in this for loop!").asAsyncSuccess()
authenticatedUser <- methodA(parameterA)
foo2 <- println("we are out of this this call!").asAsyncSuccess()
} yield {
authenticatedUser
}).unsafePerformSync
从原始代码中可以看出,您从未启动任何Task
。但是,您已经提到第一个println
将其消息打印到控制台。这可能与asAsyncSuccess
方法有关:我没有在Scalaz中找到它,所以我假设它在代码中的某个隐式类中:
implicit class TaskOps[A](val a: A) extends AnyVal {
def asAsyncSuccess(): Task[A] = Task(a)
}
如果您编写一个这样的帮助器隐式类,它将不会将有效表达式转换为惰性Task
操作,尽管Task.apply
是call-by-name。它只会转换其结果,恰好是Unit
,因为它自己的参数a
不是按名称调用的。要按预期工作,它必须如下所示:
implicit class TaskOps[A](a: => A) {
def asAsyncSuccess(): Task[A] = Task(a)
}
您也可能会问为什么第一个println
打印出来的东西,而第二个不是。这与for
-comprehensions desugaring方法调用有关。具体来说,编译器将您的代码转换为:
println("we are in this for loop!").asAsyncSuccess().flatMap(foo =>
methodA(parameterA).flatMap(authenticatedUser =>
println("we are out of this this call!").asAsyncSuccess().map(foo2 =>
authenticatedUser)))
如果asAsyncSuccess
不符合预期的Task
语义,则会立即执行println
。但是它的结果然后被包装到Task
中,它本质上只是一个包含在start函数上的包装器,而flatMap
实现只是将这些函数组合在一起而不运行它们。因此,在您调用methodA
或其他println
辅助方法之前,unsafePerformSync
或第二perform
将不会执行。但请注意,根据println
语义,第二个Task
仍然会比它应该更早执行,而不是那个。