Flushing early in Coldbox layout

Hi.

I am trying to work out the best way to go about changing coldbox's
rendering code to allow me to flush early in a layout.

So I am trying to swap out cfsavecontent and cfinclude from
renderLayout. I don't care about renderView - that can stay as it is.
I only want to the ability to flush in the layout.

I think I need to be able to process the layout line by line and write
this to a string builder. I then can hopefully access this string
builder, write it out to the output stream, flush to the client, clear
the buffer and continue rendering the layout to the buffer and at the
end, write and flush again.

Does this sound feasible? Has anyone had luck implementing early
flushing with coldbox?

Hi,

This would be interesting indeed as cfflush is pretty much useless within cfcomponent calls. I have tried several approaches before using native j2ee functions and was not successful. Hopefully you will have better luck if you come up with a strategy for this.

Also note that you can use the cold box extensions to override the core plugins with your own.

Luis F. Majano
CEO
Ortus Solutions, Corp
www.ortussolutions.com

ColdBox Platform: http://www.coldbox.org
Linked In: http://www.linkedin.com/pub/3/731/483
Blog: http://www.luismajano.com
IECFUG Manager: http://www.iecfug.com

Social: twitter.com/lmajano facebook.com/lmajano

So you didn't have any luck with native j2ee?

I can write and flush the reponseStream from the renderView function.
However - what I am having trouble with is how I process the layout
page. I have a few ideas but it's very frustrating.

Personally I don’t like cfflush…

It was introduced for some odd reason but has not got any real world applications, and most of what I have seen is used for debugging output, where other solutions are by far a better alternative.

Maybe if you could give us a better description on what you are trying to achieve we maybe able to give you a better workaround or solution.

@Andrew,
CFFlush does have some real world applications. Generating reports or exports is a great example. Many web clients will stop waiting after a while. Flushing allows them to know that you are alive and busy processing.

@Bigfellahull,
You may need to take another approach. Two strategies I would explore are:

  1. Create a special layout, which loops (or whatever) over your views and flushes directly from the layout. Not sure if this will work as I don’t know exactly what your doing.
  2. Send the layout down to the browser and make ajax request(s) for the long running content.
    Aaron Greenlee

Generating reports should or is best when using something that is designed to do reports, like cfreport or Crystal Reports.

I looked into cfflush when it was first introduced, and yes I agree it is good to show something is happening, but that percentage is very very small. And the only time I can think of any real world examples of it use is when debugging and seeing what is going on.

Personally to use it for real world customers, I would be more inclined to think of a better solution.

I would be my bottom dollar that Bigfellahull, if he explained to us what it was he was trying to achieve we could find a much better and intuitive way of doing the job.

I am trying to implement something simular to Facebook's bigpipe
technology. Basically the page is split into sections (pagelets). In
the view I call a helper function to register a pagelet which stores
the id and url to the content of the pagelet in the request scope.
This also outputs a empty holding div.

The idea is in the layout - you flush this light weight "template"
page to the client so the browser can begin to download css and
script. This also keeps the request open. Then you process these
pagelets executing them in parallel (on multiple threads) and as they
finish loading they flush down to the client as json. Javascript then
injects these pagelets into the correct div on the page.

It's a very clever technique which not only improves page load time -
it also greatly improves perceived load time as content arrives to the
client asap - rather than waiting for the entire page.

You could use ajax, but with all the extra requests I doubt it would
be very beneficial.

I had a similar issue to this when trying to implement this technique
in ASP.Net MVC as it also renders views to a buffer rather to the
stream directly (like Webform ASP.Net and CF do)
http://blog.josemanuelperez.es/2011/05/bigpipe-in-asp-net-mvc-using-razor/

You can see from the above that I solved it by grabbing the content of
the buffer, writing that to the response, flushing and then
continuing.

Aaron - your first suggestion isn't feasible because you can't flush
from a layout. renderLayout uses a cfsavecontent to render the layout
to any flush inside the layout is pointless. Hence my theory that if I
can manually read in the layout line by line, parse for any cfml,
execute it in the renderLayout method, write the resulting html to the
stream and if I encounter flush, write it to the response.

I think this is doable as the only cfml in my layout will most likely
be renderView and the flush. However that means I need to parse the
cfm file every request.

I think you can totally approach this with. Cf and Ajax loading of vielwets

I thought FaceBook was using Ajax for all that stuff.

Well I will be.

Yep they certainly are...

"At the client side, upon receiving a pagelet response via “onPageletArrive”
call, BigPipe’s JavaScript library first downloads its CSS resources; after
the CSS resources are downloaded, BigPipe displays the pagelet by setting
its corresponding placeholder div’s innerHTML to the pagelet’s HTML markup.
Multiple pagelets’ CSS can be downloaded at the same time, and they can be
displayed out-of-order depending on whose CSS download finishes earlier. In
BigPipe, JavaScript resource is given lower priority than CSS and page
content. Therefore, BigPipe won’t start downloading JavaScript for any
pagelet until all pagelets in the page have been displayed. After that all
pagelets’ JavaScript are downloaded asynchronously. Pagelet’s JavaScript
initialization code would then be executed out-of-order depending on whose
JavaScript download finishes earlier."

Yes Andrew - that is how the client handles the injection and loading
of resources. However that initial "onPageletArrive" is not made via
an ajax call. It is flushed down to the client from the server - all
in the same request.

Response.Flush("<script>bigpipe.onPageletArrive({ /*data*/ });</

");

You can read more about it here
https://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919

But the most important points from that post are that data fetching
and html generation are done server side. It is then flushed to the
client where javascript loads the css, js and sets the inner html of
the target element.

You can use ajax to achieve this effect, but as I mentioned before I
am pretty sure the extra requests you make would negate any benefit -
plus you wouldn't be able to execute and generate the html for each
pagelet in parallel which is pretty compelling point of using bigpipe.

OK - ignore the "wouldn't be able to execute and generate the html for
each
pagelet in parallel" because of course you would.

That was the article I was reading, and it specifically says that it modifies the div’s innerHTML and that can only be achieved with Ajax calls.

So I am guessing that you are saying that these Ajax calls are constant returning snippets of information, is that what you are saying?

If that is the case then you should be able to write a handler to flush the data, without using the CB renderer, in theory… But you would need to make sure that the even handler, has a norender when it is finished, again in theory.

If you read the paragraph above your quote:

"In BigPipe, the life cycle of a user request is the following: The
browser sends an HTTP request to web server. After receiving the HTTP
request and performing some sanity check on it, web server immediately
sends back an unclosed HTML document that includes an HTML tag and the
first part of the tag. The tag includes BigPipe’s JavaScript library
to interpret pagelet responses to be received later. In the tag, there
is a template that specifies the logical structure of page and the
placeholders for pagelets. After flushing the first response to the
client, web server continues to generate pagelets one by one. As soon
as a pagelet is generated, its response is flushed to the client
immediately in a JSON-encoded object that includes all the CSS,
JavaScript resources needed for the pagelet, and its HTML content, as
well as some meta data."

You can see this is not ajax. The initial flush is a unclosed page -
which keeps the request open. The server then processes the pagelets
and flushes the json encoded content wrapped in a javascript function.
When this is flushed to the client, the browser executes the
javascript. You can verify this for yourself by opening fiddler and
browsing to facebook.

So this brings me back to my original issue of flushing in the layout.
I need to keep the request open.

The easiest way is to use ajax like you have suggested - but I would
like to find a way to replicate facebook's method in coldbox.

Well if it is not Ajax, then how does it convert the JSON-encoded object?

Browsers can’t do this natively.

I don't understand. Convert the object to what?

This is what is flushed down to the client in my test .net app.

<script>bigpipe.onPageletArrive({"ID":"pagelet-topposts","Content":" \r
\n\u003csection id=\"topPostsContainer\" class=\"clearFix\"\u003e\r\n
\u003carticle class=\"topPost\"\u003e\r\n \u003ca href=\"http://
localhost:52127/2011/06/11/a-news-story-no-game/\"\u003e\r\n
\u003csection class=\"thumbWrapper\" style=\"background: url(/media/
images/4/sftek.png) 50% 50% no-repeat;\"\u003e\r\n \u003cdiv\u003e
\u003ch2\u003eA news story - no game\u003c/h2\u003e\u003c/div\u003e\r
\n \u003c/section\u003e\r\n \u003c/a\u003e\r\n \u003c/article\u003e\r
\n \u003carticle class=\"topPost\"\u003e\r\n \u003ca href=\"http://
localhost:52127/2011/06/11/another-post-2/\"\u003e\r\n \u003csection
class=\"thumbWrapper\" style=\"background: url(/media/images/3/
sftek.png) 50% 50% no-repeat;\"\u003e\r\n \u003cdiv\u003e
\u003ch2\u003eAnother Post 2\u003c/h2\u003e\u003c/div\u003e\r\n \u003c/
section\u003e\r\n \u003c/a\u003e\r\n \u003c/article\u003e\r\n
\u003carticle class=\"topPost\"\u003e\r\n \u003ca href=\"http://
localhost:52127/2011/06/11/another-post/\"\u003e\r\n \u003csection
class=\"thumbWrapper\" style=\"background: url(/media/images/2/
sftek.png) 50% 50% no-repeat;\"\u003e\r\n \u003cdiv\u003e
\u003ch2\u003eAnother Post\u003c/h2\u003e\u003c/div\u003e\r\n \u003c/
section\u003e\r\n \u003c/a\u003e\r\n \u003c/article\u003e\r\n\u003c/
section\u003e","Css":null,"Js":null});</script>

Then in the bigpipe js file

var BigPipe = function (count) {

     var d = document,
        pagelets = []; /* registered pagelets */

     var onPageletArrive = function (p) {
         count = count || p.count;

         /*js and css loading removed for simplicity*/
        document.getElementById(p.ID).innerHTML = p.Content;
};

Now - this JSON blob COULD be retrieved via js using XMLHttpRequest
for example - but the point am I trying to make - in facebook's case
it isn't. The request stays open and this script tag is flushed to the
client.

"modifies the div's innerHTML and that can only be achieved with Ajax
calls."

If this is your definition of Ajax then we have wildly different
definitions! Ajax is communicating with the server without affecting
the current state of the page, right? I don't see how innerHTML falls
under the banner of Ajax. If you had a static array on the page which
you dynamically injected into the DOM on certain events - would you
class that as Ajax. I wouldn't.

No what I am trying to say is that what is being flushed down, needs to be parsed by some JS. The only way that I can see that happening is that an Ajax call is made to continually async the data, if they are async’ing it. Then when a packet is received it has to then be taken from JSon, decoded and then placed into some container that already exists.

I am not saying you are wrong…

I am struggling to understand how they can do this without JS / Ajax.

Otherwise what is the point, you may as well leave it as one full html in the first place. It wouldn’t save anything in my view.

That is what I am trying to get my head around.

I just can’t see it being done any other way, a normal page request is the same thing. It keeps bring data down the pipe until it is all received and then it is rendered, if what you are saying is correct then the basic layout is downloaded, then they see if a packet exists at the end of the request, or at the end of the file then parse it and move it to where it has to go.

It does open up some questions, but I am going to bet my bottom dollar there is Ajax driving this whether we see it or not.

It’s pretty simple. The Layout needs to be fully rendered, and therefore the body tags and DIVs all need to be closed. That is then flushed, so the Scaffolding of the layout is all in place.

Then after that is all flushed, a viewlets are sent and flushed as and when the server has created them. This is sent as a JSON object in a script tag in the resulting flushes. It triggers a function which deserializes the JSON packet and puts the html with the packet into the relevant viewlet “section” on the page, using javascript.

There’s no need for any ajax.

Watch this.

Tom is right.

Basically bigpipe improves load time and also perceived load time. It
improves load time because that early flush allows the browser to
begin downloading css and js before the page is fully rendered. Also -
processing the pagelets in parallel on the server allow the page to
load quicker.

It improves perceived load time because the user doesn't have to wait
for the page to fully load before they see content. As each pagelet
loads, it is displayed on the page.