Search code examples
htmlperlprogressive

unable to do progressive rendering


Years ago I wrote CGI programs at previous jobs that relied on progressive rendering, since those CGI programs could take a long time (minutes) to run, producing a line of output approx every second. I find that today, I cannot get progressive rendering to occur even with the simplest example.

I've seen a lot of suggestions on this topic about where to put CSS, scripts, etc. However, the trivial example below has none of that.

I don't see anywhere where browsers have an option to affect progressive rendering. I have tried this on several systems/devices with several browsers (chrome, firefox, opera), all with the same result.

Below is a trivial example that I expect to produce some output every 2 seconds, but instead it renders when the whole document is complete. Am I missing something obvious?

#!/usr/bin/env perl

select(STDOUT); $| = 1;     # don't buffer stdout

print "Content-Type: text/html\; charset=ISO-8859-1\n\n" ;
print "<html> <head> <title> Testing </title> </head> <body>\n" ;

my $message = "<code>" .
    "Why doesn't this render immediately? <br>\n" x 5 .
    "</code>\n" ;

for ( my $i=0 ; $i < 5 ; $i++ ) {
    print "$message\n" ;
    sleep(2) ;
}
print "</body></html>\n" ;

Solution

  • Your web server is likely buffering the response. $| = 1; sets up STDOUT to be autoflushed each time you print, eliminating the effects of the buffering in your script, but you also need to consider buffering that's happening in your web server.

    There's no command or character sequence to flush the buffer, but you could simply just send a sufficient amount of data to fill the buffer so that it flushes on its own.

    Just send inconsequential content, like a bunch of spaces:

    print " " x 1024 * 8;
    

    How much data you need to send depends on how large the buffers are configured to be in your web server. Typical buffer sizes are 4KiB or 8KiB, but be aware that if your server gzips your script's response then you will need to print considerably more (perhaps around 8MiB of space characters) in order to fill the server's buffers because the buffers will be filled with the compressed response.

    Of course, you could also just disable the buffering in your server. How you do that depends on the web server. For nginx, take a look at X-Accel-Buffering.