JSON Streaming Output

I recently put together a simple little bit of code to handle streaming large amounts of JSON formatted data to the browser.

In order for you to see any benefit from this, you will need to have the following scenario.

You have a response you’re sending back with some meta information about the response – maybe a response code, or error messages or a single record.

You also have a number of rows to send back as a member of the main JSON object.

These rows don’t all need to be the same object, but you can only have a single variable that you stream.

This allows you to fetch and send a single database row at a time instead of building up a huge response object in memory on the server.

It builds up a response that looks like this (the data in “rows” is streamed one line at a time):

{
    "success":true,
    "rows":
    [
        {"id":1,"random_data":"a6b1e15cc6523e87cb8d5a6a0ea39dbc61842b23"},
        {"id":2,"random_data":"12ae19125e2182294433e835ee8dc7e403154fdd"}
    ]
}

Advertisements

COMET Update – Workaround Blocked Connections

In my instance it turns out the connection wasn’t blocked because of browser issues – it was completely server side.
In my comet controller, before I got into my JS output loop, I issued a session_write_close();

That’s all it took.
Thanks, stackoverflow

An obvious JavaScript problem with solution (jQuery)

Today I was working with jQuery in a JavaScript file, and jQuery kept coughing up a strange error that was puzzling.

elem.nodeName is undefined

Inspecting the backtrace in firebug led me to this line

$( 'td.qty_sel :input' ).live( 'change', ns.viewModel().qtyChange() );

Seasoned JavaScript developers will probably spot the problem immediately, but it took me some time (and a developer friend) to figure it out.

He said, “because your function is not a function reference, it’s a function call

A few seconds and a corrected script later and it was working.

$( 'td.qty_sel :input' ).live( 'change', ns.viewModel().qtyChange );

Take away:

  1. When referencing existing functions in a jQuery event handler, don’t call the function ¬†(duh) – remove the parens (duh).

ūüôā

jQuery Integer Only Text Inputs using qTip for notification

I needed a great, unobtrusive way to notify a web site visitor that they can only enter whole numbers into fields on a web form. This is the JavaScript I came up with using jQuery and qTip  This is easily modified to support numeric characters of any sort Рdecimal points, commas, whatever you want.  It does not enforce any particular rules Рit is primarily a keystroke filter.

I allow numbers and navigation keys, but disallow everything else. The code is documented inline.

Please don’t forget that if you use this to not rely on it for anything except relieving user frustration. You should always do server side validation as well

And this is the way it looks in my project:

.

One thing I should note: I’m using this together with¬†Knockout.js¬† without any weird side effects – they are working nicely together.

$(function()
{
    $('input.intOnly' ).live( 'paste',
    function(event)
    {
        // we could loop across the value and validate it, but I'm too lazy
        event.preventDefault();
    });

    $("input.intOnly").live( 'blur',
    function( event )
    {
        $(this).qtip('destroy');
    });

    $("input.intOnly").live( 'keydown',
    function( event )
    {
        if (
            event.keyCode == 46  || // delete
            event.keyCode == 8   || // backspace
            event.keyCode == 9   || // tab
            event.keyCode == 224 || // command key on mac
            event.keyCode == 18  || // alt key
            event.keyCode == 16  || // shift key
            event.keyCode == 17  || // control key
            ( event.keyCode >= 48 && event.keyCode <= 57  ) || // numbers
            ( event.keyCode >= 96 && event.keyCode <= 105 ) || // numeric keypad
            ( event.keyCode >= 37 && event.keyCode <= 40  )    // arrow keys
        )
        {
            return;
        }
        event.stopImmediatePropagation();
        event.preventDefault();
        $(this).qtip(
        {
            content: 'Only whole numbers are allowed.',
            show: { ready: true },
            hide: { fixed: true, delay: 100000 }
        });
    });
});

PHP based COMET Using iframes

So I’m doing some research into, and will probably be using COMET for a project I’m working on. Yes, I know that the Apache-PHP combination is not the best for COMET, however this will be on an administrative dashboard with one or two simultaneous users at most. ¬†I’m no COMET expert – this is my first foray into the technology. ¬†If I learn amazing things while doing a live implementation I’ll write more articles.

While searching I ran across several tutorials and some code, but nothing that was a simple 2 file “Here’s how it’s done” example.

The basic premise (this is not new stuff – I ran across stuff from the mid 2000’s while searching) is that you have an iframe¬†that loads a long-running PHP script that is generating <script> tags. ¬†The JavaScript in these tags must reference the parent document. ¬†In my test code I’m referencing a function defined in the parent document.

Some takeaways:

  1. If the script that’s referenced by your iframe¬†doesn’t output enough data before it starts outputting <script> tags, you’ll see a delay until some sort of buffer is filled up. ¬†I’m blaming Firefox, but I’m not certain as I didn’t investigate further. ¬†You’ll notice a bunch of white space in my sample code – that’s a whole ton of spaces to stop the delay I was seeing in Firefox.
  2. On localhost this is very fast. ¬†I had to introduce a usleep into the code so that it wouldn’t be so fast as to be unusable. ¬†I haven’t tested against a remote web server, but I can assure you this will be dramatically faster than ajax polling.
  3. Firefox’s javascript engine seems to process the <script> tags being returned in the iframe faster than the DOM is able to update. I view this as good news.
  4. You must output the opening and closing script tags each time you want to update the browser. ¬†Leaving them out will cause the browser to wait until the request is loaded – the opposite of what we’re trying to accomplish.

The example code is not an infinite loop – it’s a long running script (just a very long for loop). ¬†In practice I’ll be using other factors to determine when to break out of an output loop. ¬†The project requirements call for this to be running for hours so we’ll find out if that tests the limits of what this approach can handle.

Download the code