In my method1, I need to call another method2 asynchronously, which returns Option (result1). Than, if result1 is empty, I need to call another method3 asynchronously, but if result1 is NOT empty, I just need to return it.
Here is the method:
def signIn(username: String): Future[User] = {
for {
foundUser <- userService.findByUsername(username) // this method returns Future[Option[User]],
// foundUser is Option[User]
user <- if (foundUser.isEmpty) {
val newUser = User(username = "User123")
userService.create(newUser).map(Some(_)) // this method returns Future[Option[User]]
}
else
// Here I want to return just foundUser, of course, it is not possible.
// IS THIS APPROACH CORRECT?? DOES THIS LINE CREATE ASYNCHRONOUS CALL?
Future.successful(foundUser)
} yield user
}
Question is:
Future.successful(foundUser)
- is this approach correct in the code above? Does this line create asynchronous call? If so, how to avoid it? I've already fetched foundUser asynchronously, and I don't want to make additional async call just to return already fetched value.
By default, futures and promises are non-blocking, making use of callbacks instead of typical blocking operations. To simplify the use of callbacks both syntactically and conceptually, Scala provides combinators such as flatMap , foreach , and filter used to compose futures in a non-blocking way.
Handle the result of a future with methods like onComplete , or combinator methods like map , flatMap , filter , andThen , etc. The value in a Future is always an instance of one of the Try types: Success or Failure.
Promise is an object which can be completed with a value or failed with an exception. A promise should always eventually be completed, whether for success or failure, in order to avoid unintended resource retention for any associated Futures' callbacks or transformations. Source Promise.scala. AnyRef, Any.
You can't unwrap the value of a Future because a Future represents the result of an asynchronous computation that may or may not be available yet. By default, futures and non-blocking, encouraging the use of callbacks instead of typical blocking operations.
Future.successful
doesn't queue an additional function on the provided ExecutionContext
. It simply uses a Promise[T]
to create a completed Future[T]
:
/** Creates an already completed Future with the specified result.
*
* @tparam T the type of the value in the future
* @param result the given successful value
* @return the newly created `Future` instance
*/
def successful[T](result: T): Future[T] = Promise.successful(result).future
As a side note, you can reduce the amount of boilerplate using Option.fold
:
def signIn(username: String): Future[User] =
userService
.findByUsername(username)
.flatMap(_.fold(userService.create(User(username = "User123")))(Future.successful(_))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With