Async Model Data
In real applications you quite often have to deal with model data that is asynchronously loaded or updated. Usual approach would be to use
indicate whether data is there or not, but then you cannot deal with error situations. Using
Either[ErrorType, Option[A]] or
Try[Option[A]] gives your some
control over errors, but if you consider refreshing old data and getting an error back, what should the result be? Not to mention knowing how long the async
operation has been running and notifying the user when it has been delayed for too long. Clearly the existing data containers are not enough for this.
Pot[+A] represents potential data that may exist in seven different states as seen in the picture on the right.
Pot provides you with the same interface as
Try, making it very easy to use in your existing application code. Things like for comprehension,
getOrElse or even
recover are supported.
Pot is immutable and you have to create a new
Pot when the state or content changes.
Pot usually starts as an
Some), depending on whether you have the data available or not. You can use the
method to create a correctly typed
var myData = Pot.empty[String] // myData is now Empty
When you make an async call to fetch data, change the state to
Pending with the help of
myData = myData.pending() // myData is now Pending
Assuming you get a successful response from the server, you can change the state to
myData = myData.ready(data) // myData is now Ready(data)
In case something went wrong, you can store the exception in the
myData = myData.fail(exception) // myData is now Failed(exception)
When you are ready to refresh your
Ready data, you again call
pending but this time it results in a
PendingStale indicating that old data is still there to be
used while new data is fetched.
myData = myData.pending() // myData is now PendingStale(data)
In case the async call gets new results, the state goes to
Ready(newData) but if something goes wrong, you'll end up with
FailedStale containing the
myData = myData.fail(exception) // myData is now FailedStale(data, exception)
If the data you are trying to fetch does not exist, you can use
Unavailable to indicate that.
myData = myData.unavailable() // myData is now Unavailable
Pot exposes its state via following functions.
def isEmpty: Boolean def nonEmpty = !isEmpty def isPending: Boolean def isStale: Boolean def isFailed: Boolean def isReady: Boolean def isUnavailable: Boolean def state: PotState
You can query specific state via
isX functions, or use
state for matching. Note that
isEmpty means there is no data in the
Pot, so states
Failed, in addition to
Empty, all return
Pot works like an
Failed work like
The pending states of
Pot store a time stamp when created. You can access this through
startTime, or you can directly get the duration of the operation
duration(currentTime). This is useful in an user interface, where you'll want to show an indicator if the operation is taking too long. If
an operation fails and you retry it, the
startTime will remain the same, giving you the total duration of the retried operations.