Blogtronica

Thoughts, ramblings and insights

netronica.io

Non JQuery JsonP calls

I have had to work on a JavaScript heavy project that had a .js file that any third party could include on their website, It could not use Jquery because it needed the ability to be embedded on third party sites, and for reasons of performance it had to make ajax calls to pregenerated json files.

So the simple way of invoking a jsonp call is:

window['NAMEOFCBFUNCTION'] = function (o) {  
//Callback logic here
alert(o.someJsonKey)  
}

document.getElementsByTagName('body')[0].appendChild((function () {  
var s = document.createElement('script');  
s.type = 'text/javascript';  
s.src = Url;  
return s;  
})());

And the jsonp file would look like

NAMEOFCBFUNCTION({someJsonKey:"someJsonValue"})  

However in my case the .js file could theoretically be included on the same page multiple times, and could make multiple jsonp calls as well, but since the callback function name is hardcoded, I couldn't reassign the callback function until the last call was done or start another jsonp call until the previous one was done, so I came up with the following logic that uses a queue to send off the jsonp requests and calling the associated callback functions in the correct order before firing off the next queued jsonp call, whilst also keeping context as well!

function NameOfMyMainClass () {  
// All sort of logic here....
}

 if (!window['NAMEOFCBFUNCTION']) {
        window['NAMEOFCBFUNCTION'] = function (o) {            
            var callbackargs = window.CONTEXTQUEUE.shift();            
            callbackargs.success && callbackargs.success.apply(callbackargs.context, [o]);
            if (window.CALLBACKQUEUE && window.CALLBACKQUEUE.length > 0) {
                var args = window.CALLBACKQUEUE.shift();
                args.context.GetJSON.apply(args.context, [args.url, args.success])
            }
        };   
    }

    NameOfMyMainClass.prototype.GetJSON = function (Url, success) {        
        var cntxt = this;

        if (window.CONTEXTQUEUE && window.CONTEXTQUEUE.length > 0) {
            if (!window.CALLBACKQUEUE) window.CALLBACKQUEUE = new Array();
            window.CALLBACKQUEUE.push({
                url: Url,
                success: success,
                context: cntxt
            });
        }
        else {            
            if (!window.CONTEXTQUEUE) window.CONTEXTQUEUE = new Array();
            window.CONTEXTQUEUE.push({ context: this, success: success });                        
            document.getElementsByTagName('body')[0].appendChild((function () {
                var s = document.createElement('script');
                s.type = 'text/javascript';
                s.src = Url;
                return s;
            })());
        }
    };

Disclaimer, this was ported from my old blog, which is now dead, there was not much worth porting from it, but this post might be of use to someone with a similar problem

Photo credit https://www.flickr.com/photos/gruenemann/4055967157