A reader sent me a question earlier today about handling a slow process. He had a page where a particular CFC call was taking 2-3 seconds to run. He needed the output of the CFC to be in the middle of the page. He used cfflush above the call to at least present something to the user, but this wasn't optimal. They saw half a page load, then a delay, and finally the rest of the page. I suggested simply switching to an Ajax based solution and offered to create a quick demo so he could see it in action. As I'm an expert at writing slow code, I thought this would be a fun way to spend lunch. Let's start with the non-Ajax version first.
<h2>This is a test page</h2>
<p>
This is some content that is above the slow part. I'm going to use cfflush to expose the content earlier.
You should see it while CF then works on the slow part.
</p>
<cfflush>
<cfset ob = createObject("component","foo")>
<cfoutput>
<p>
#ob.doSomethingSlow()#
</p>
</cfoutput>
<p>
This is the end of the file. Nothing dynamic, nothing really interesting.
</p>
As you can see, the page contains a header and footer that is simple HTML. In the middle is a cfflush and then a call to my component. Let's take a look at the component.
<cfcomponent output="false">
<cffunction name="doSomethingSlow" output="false" returnType="any">
<cfset sleep(5000)>
<cfreturn "I'm down with the slow process. The result was foo.">
</cffunction>
</cfcomponent>
Yeah, I won't bother going over that. As you can see, it just uses the sleep function to pause for 5 seconds. (I was going to link to this demo. It works fine locally. Oddly it did not on production. I wonder if IIS7 is doing something to block the flush action? Actually it may be working - my connection seems slow enough today where the 5 seconds may be too short.) If you run this code you should see the first half of the page, a delay, and then the rest of the page.
Ok, so how can we switch this to an Ajax-based solution? You guys know I'm somewhat of a jQuery Fanboy now, but the simplest solution is to just use what's built in to ColdFusion 8. Consider:
<h2>This is a test page</h2>
<p>
This is some content that is above the slow part. I'm going to use cfflush to expose the content earlier.
You should see it while CF then works on the slow part.
</p>
<cfdiv bind="url:slow.cfm" />
<p>
This is the end of the file. Nothing dynamic, nothing really interesting.
</p>
I've gotten rid of the flush, and just moved the createObject/function call to slow.cfm. You can see this in action here.
Pretty simple? I couldn't not write a jQuery example, so here it is, one more time, with jQuery:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#slowdiv').html('Loading...')
$('#slowdiv').load('slow.cfm')
})
</script>
</head>
<body>
<h2>This is a test page</h2>
<p>
This is some content that is above the slow part. I'm going to use cfflush to expose the content earlier.
You should see it while CF then works on the slow part.
</p>
<div id="slowdiv"></div>
<p>
This is the end of the file. Nothing dynamic, nothing really interesting.
</p>
</body>
</html>
Just a slight bit more complex. 4 or so lines more. Not bad though. Also, you have more control over the loading message. You can see this in action here.
Hope this helps!