玩 Scala 2.4 链接异步调用

Play Scala 2.4 linking asynchronous calls

我正在尝试弄清楚如何 link 多个异步调用和 return 结果。我目前正在尝试先异步用户数据,然后异步更新用户数据和 return 结果,但它似乎不起作用:( 我使用了 map { result => Ok(result)},但 play 仍然认为我在 returning 一个对象。有帮助吗?

def updateUserData() = Action.async { implicit request =>
updateUserForm.bindFromRequest.fold(
errors => Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(errors, Option(""), Option("")))),
{
  case (userData) =>
    request.session.get("email") match {
      case Some(email) =>
        getUser(email, userData.curent_password) map { userCheck =>
          if (userCheck) {
            updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
              Ok("please")
            }
            //val e = updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map {result => Ok("")}

            // user is valid now update the user data

            // call removeAuth to log out

            // redirect to home
            ///Ok (updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result => result})
            //Redirect(routes.settings.index()).addingToSession("email" -> email)
          } else {
            BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option("")))
          }
        }
      }
  })
}

我遇到问题的主要部分是这部分。我认为这是一些语法问题。有人可以帮忙吗? 谢谢

updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
  Ok("please")
}

问题出在您的类型上,它们与所需的类型不匹配。

.fold 必须在两个分支(错误和成功分支)中产生 Future[Result]

在成功的表单绑定分支中你有这个:

case (userData) => ... // The ... must evaluate to Future[Result]

查看您的第一个操作,我们发现:

request.session.get("email") match {
  case Some(email) => ...
}

这里的一个大问题是 None 案例没有得到处理! (但这不会导致类型不匹配)。有类似下面的东西将解决这个问题:case None => Future.successful(BadRequest(...))

所以继续:在 Some 你有以下内容:

getUser(email, userData.curent_password) map { userCheck =>
  if (userCheck) {
    updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
       Ok("please")
    }
  } else {
    BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option("")))
  }
}

这就是问题所在:

getUser 将 return 与 Future[X] 并且当你映射它时你将有 Future[Y] 其中 Y 将是 userCheck => ... 的计算结果为。

在这种情况下,类型完全混淆了,因为当你在真分支上做 if(usercheck) 时,你在假分支上做 Future[Result],你有 Result。因此,类型在两个分支上都不对齐,这是一个大问题,编译器将从中推断出 Any

要解决此问题,请在 false 分支中创建一个未来:Future.successful(BadRequest(....))

好的,既然我们解决了最内在的类型问题,让我们开始倒退。在里面我们有 Future[Result],如果我们返回一级(在 getUser() 之前),那么我们将有 Future[Future[Result]]。同样,这不是我们想要的,因为我们需要 Future[Result].

解决这个问题的方法是 flatMap 而不是 map,因为使用 flatMap 时,当您需要 return 相同的容器类型时,它会将其展平。一个简单的例子来理解这一点:

Seq(1, 2, 3).flatMap(i => Seq(i, i))
// res0: Seq[Int] = List(1, 1, 2, 2, 3, 3)

Futures的情况下:

import scala.concurrent.Future   
import scala.concurrent.ExecutionContext.Implicits.global
Future(1).flatMap(i => Future(i*2))
// res1: scala.concurrent.Future[Int] = [....]

所以我们看到我们没有双重嵌套,只有一个Future

回到你的例子,这将是我更新后的代码,效果会更好:

def updateUserData() = Action.async { implicit request =>
  updateUserForm.bindFromRequest.fold(
    errors => Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(errors, Option(""), Option("")))),
    {
      case (userData) =>
        request.session.get("email") match {
          case Some(email) =>
            getUser(email, userData.curent_password).flatMap { userCheck =>
              if (userCheck) {
                updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
                  Ok("please")
                }
              } else {
                Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option(""))))
              }
            }
        case None => Future.successful(BadRequest) // FIXME: Implement as you wish
        }
    })
}