CallbackをFuture化する
def profileImg(imgUrl: String):Future[Array[Byte]] = {
val p = Promise[Array[Byte]]()
val f = p.future
SNSClient.getImageAsync(imgUrl, new SimpleCallback[Array[Byte], Exception] {
override def onSuccess(imgData: Array[Byte]): Unit =
p.success(imgData)
override def onFailure(e: Exception): Unit =
p.failure(e)
})
f
}
19.
Futureのエラー処理
val json =profileJsonFuture(“https://facebook.com/xxx")
.recoverWith { case t =>
t.printStackTrace()
profileJson("https://twitter.com/xxx")
}
20.
Future化したものを合成
val dataFuture: Future[Array[Byte]]=
for {
json <- profileJsonFuture(“https://facebook.com/xxx")
.recoverWith { case t =>
t.printStackTrace()
profileJsonFuture("https://twitter.com/xxx")
}
imgUrl <- parseFuture(json)
data <- profileImgFuture(imgUrl)
} yield data
(余談)ReactiveXのDocにも…
Callbacks Have TheirOwn Problems
Callbacks solve the problem of premature blocking on
Future.get() by not allowing anything to block. They are
naturally efficient because they execute when the
response is ready.
But as with Futures, while callbacks are easy to use
with a single level of asynchronous execution, with
nested composition they become unwieldy.
http://reactivex.io/intro.html
Observable同士を合成
val dataObservable: Observable[Array[Byte]]=
for {
_ <- onClick(Button)
json <- Observable.from(profileJson(“https://facebook.com/xxx")
.recoverWith
{ case t =>
t.printStackTrace()
profileJson("https://twitter.com/xxx")
})
imgUrl <- Observable.from(parse(json))
data <- Observable.from(profileImg(imgUrl))
} yield data
Scalaz Task化したCallback
def profileJsonTask(url:String): Task[String] =
Task.async[String] {
f =>
SNSClient.getProfileAsync(url, new SimpleCallback[String, Exception] {
override def onSuccess(json: String): Unit = f(/-(json))
override def onFailure(e: Exception): Unit = f(-/(e))
})
}
dataTask.runAsync {
case /-(data) => println(data)
case -/(e) => e.printStackTrace()
}
Task.async[A](register: ((Throwable / A) => Unit) => Unit): Task[A]
36.
Task化したcallbackを合成
val dataTask: Task[Array[Byte]]= for {
_ <- onClickTask(Button)
json <- profileJsonTask(“https://facebook.com/xxx")
.handleWith { case t =>
t.printStackTrace()
profileJsonTask("https://twitter.com/xxx")
}
imgUrl <- parseTask(json)
data <- profileImgTask(imgUrl)
} yield data
dataTask.runAsync {
case /-(data) => println(data)
case -/(e) => e.printStackTrace()
}
Freeモナド化したCallback
sealed abstract classProgram[A] extends Product with Serializable
final case class OnClick(button: Button) extends Program[Button]
final case class ProfileImage(imageUrl: String) extends Program[Array[Byte]]
final case class ProfileJson(url: String) extends Program[String]
final case class ParseJson(json: String) extends Program[String]
import ScalazTaskExample._
val interpreter: Program ~> Task =
new (Program ~> Task) {
override def apply[A](fa: Program[A]) = fa match {
case OnClick(button) => onClickTask(button)
case ProfileImage(imageUrl) => profileImgTask(imageUrl)
case ProfileJson(url) => profileJsonTask(url)
case ParseJson(json) => parseTask(json)
}
}
val task: Task[String] = Free.runFC(liftFC(ProfileJson(“https://facebook.com/xxx"))(interpreter)
task.runAsync {
case /-(data) => println(data)
case -/(e) => e.printStackTrace()
}
46.
Freeモナド化したCallback
のエラー処理
def getTaskFrom(interpreter: Program~> Task): Task[Array[Byte]] =
for {
json <-
Free.runFC(
for {
_ <- liftFC(OnClick(Button))
json <- liftFC(ProfileJson("https://facebook.com/xxx"))
} yield json
)(interpreter).handleWith { case t =>
t.printStackTrace()
profileJsonTask("https://twitter.com/xxx")
}
data <-
Free.runFC(
for {
imgUrl <- liftFC(ParseJson(json))
dt <- liftFC(ProfileImage(imgUrl))
} yield dt
)(interpreter)
} yield data