Web Development

Lift code is easy to read and maintain. Lazy loading, parallel execution, simple push mechanics, and REST support are just a few of Lift's stand-out benefits.

In the first installment in this two-part series on the Lift Web Framework, I explained how to set up a project with Lift and how to work with the framework's concept of snippets. In this article, I explain how take advantage of lazy loading, parallel execution, Comet server pushes, wiring, and REST support.

Rendering Snippets with Lazy Loading

Sometimes, a snippet takes a long time to render and you don't want to wait for it to return a Web page to the Web browser. Lift supports lazy loading of snippets to assist you in this scenario. You need only add some simple markup to a snippet and Lift will do the necessary work to return the Web page to the Web browser quickly, displaying a spinning icon until the snippet finishes computation, and then delivers the necessary HTML to the Web browser.

The following listing shows a new version of the TrendTopic.hottest method with a line that calls Thread.Sleep to simulate a computation that requires three seconds:

The next listing shows a new version of the Game.render method with a line that calls Thread.Sleep to simulate a computation that requires two seconds. (This way, each snippet that is rendered in the view takes a different amount of time to perform the computation and so will demonstrate visually how lazy loading works.)

Now that the two methods invoked by the snippets in the index.html view require a few seconds to be processed, the user would have to wait a long time for the page to be rendered in the Web browser. Thus, you need to enclose the markup that executes the snippet within the following markup to instruct Lift to use lazy loading for the snippet:

<div data-lift="lazy-load">
</div>

The following lines show the new version of the /src/main/webapp/index.html view that renders the two snippets with lazy loading:

Now, when you navigate to http://localhost:8080/index to view the Web page with the rendered dynamic content of the snippets, you will see two spinning icons because the methods are sleeping for a few seconds (see Figure 1).

Figure 1: The index.html view displaying the spinning icons for the two snippets with lazy loading.

After two seconds, the Game.render method stops sleeping and Lift will deliver the resulting HTML for the snippet to the Web browser with the game name and the highest score. The TrendTopic.hottest method goes on sleeping for a while longer, so the spinning icon for the snippet will still be visible (see Figure 2). Finally, Lift delivers the resulting HTML for the snippet and you will see the same content as in the previous version without lazy loading.

Figure 2: The index.html view displaying the results for one of the snippets with lazy loading.

Rendering Snippets with Parallel Execution

When snippets take a long time to render, you can also instruct Lift to execute specific snippets in parallel during the rendering of the Web page. Lift will fork off an additional thread for each snippet that must be rendered in parallel, and when all the parallel renders finish, Lift sends the final rendered page to the Web browser.

As you might guess, you just need to add some simple markup that sets the lift:parallel attribute to true and Lift will do the necessary work to execute each snippet that requires parallel execution in a different thread.

The following lines show the new version of the /src/main/webapp/index.html view that renders the two snippets with parallel execution in two different threads:

Now, when you navigate to http://localhost:8080/index to view the Web page with the rendered dynamic content of the snippets, you will only have to wait about three seconds to view the results because Lift renders both snippets in parallel. If you change the value of the lift:parallel attribute to false, you will notice that the Web page will require at least five seconds to appear in the Web browser because one snippet requires two seconds and the other requires three seconds to render.

Working with Comet Server Pushes

You often need to update something like the "hottest trend" topic in a Web page as the real-time information changes. I'll take advantage of Comet's server pushes to demonstrate how you can write just a few lines of code to easily update content when something changes.

The following listing shows the code for a new CometTrendTopic.scala file that defines the CometTrendTopic class with three methods: defaultPrefix, render, and lowPriority. Notice that the code is included in the code.comet package, which is the default package for Comet actors based on the rules I defined in Boot.scala in the previous article. The file also defines the TrendTopic case object. You must place the file in src/main/scala. I've included the most frequently used imports for new classes that extend the CometActor trait.

The following lines show the new version of the /src/main/webapp/index.html view that renders a Comet component of type CometTrendTopic to display the hottest trend topic, which the server will update with a push every five seconds:

The markup within the div of the lift:comet?type=CometTrendTopic class defines two placeholders for the updates that the Comet component performs through binding: trend:hottest and trend:time. The prefix for both placeholders is trend. CometTrendTopic extends the net.liftweb.http.CometActor trait and overrides the defaultPrefix method to return the default prefix string, trend, in a full box.

The render method returns a scala.xml.NodeSeq by returning the result of two chained calls to the CometActor.bind method. Notice the nice syntax to replace trend:hottest with a span named hottest and trend:time with a span called time:

Lift uses many helpers to make it easy for you to bind HTML elements to the placeholders you define in the markup for your Comet component. It is easy to read and understand the HTML that the code is binding to the hottest and time placeholders because it is the same HTML you would write in the HTML editor (without quotation marks). You can also use the CSS selector transforms I introduced in the first article in this series. However, in this case, I wanted to show you another way of building a NodeSeq.

Schedule.schedule(this, TrendTopic, 5 seconds) calls the net.liftweb.util.Schedule.schedule method to schedule an update every five seconds. The target actor is this, the message is the TrendTopic case object, and the delay is five seconds. Notice the convenient way of specifying the 5 seconds timespan. The delay parameter is of type net.liftweb.util.Helpers.TimeSpan. A TimeSpanBuilder case class allows you to build a TimeSpan with an amount and a method that specifies the time unit. Thus, 5 seconds is equivalent to 5.seconds. You might specify 1 second because second is also defined. If you still haven't fallen in love with Scala, Lift provides many features that might make that happen.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!