In the Lift project I’m currently working on, we have a long-running background task which outcomes need to be displayed on screen once computed. I would like to describe a simple enhancement for Lift bindings that allows to bind
Future[T] using CSS selectors the same way as any other simple type.
The traditional request-response lifecycle model assumes, that the client side is responsible for initiating the interaction sending HTTP request. Client’s request is processed by server that prepares and sends back HTTP response. At this point interaction is over, unless client sends another request that starts completely new request/response lifecycle.
In case of
Future[T], this traditional model is not enough. It’s the server side that is aware when
Future evaluation is completed so, theoretically, the server side should initiate the interaction. This behaviour can be simulated using Comet. The Comet model is based on long-running HTTP request that allows server to push data to the client. When client receives data from server, new long-running HTTP request is triggered. This way, we can simulate behaviour that server side is capable of initiating the interaction and may send notifications to client at any time.
Using Comet is sometimes not desirable, though. In my case, there is a very simple Lift snippet with only some part of DOM lazy loading. This lazy-loading part is computed by a relatively long-running background task (comparing to the page load time). Once computed, information is never updated, so only one “server push” is required.
Because I didn’t want to use Comet, I had to come up with my own solution. What I wanted to achieve was the possibility to bind
LAFutures (Lift wrapper for
Future) using CSS selectors just like in case of simple types:
Important requirement was that the code containing
Future bindings might be rendered using
IdMemoize transform. It means that there was absolutely no guarantee, that
Futures were bound to static DOM elements visible at the first render time and never updated. Part of DOM containing nodes to which
Futures were bound could be re-rendered at any time and after each such operation, Lift should attempt to resolve these
The code below is all you need to make it happen – the only thing required to do is to
import FutureBinds._ into your snippet and you are free to bind
Futures using CSS selectors just like in the example code above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
Each one second, client asks server “has
Future completed?”. If so, server tells client to update its DOM with
Future evaluation result. Otherwise, server says “Not yet. Please ask me again later”.
Alternative approach for binding
Futures has been presented by Antonio in his lift-future-canbind-example on GitHub.
It’s very clever idea that takes advantage of Lift’s
<lift:lazy-load> mechanism. The
FutureBinds code in that example looks much simpler but there is one important limitation. Under the hood, lazy load uses Lift’s comet and comets can’t be sent down to the client via AJAX at the moment. That’s just framework limitation. So even if we agree on using comet to handle
Future bindings internally, we will not be able do render code containing
Future bindings dynamically with
Sample application with my
FutureBinds implementation is available on GitHub.