Wednesday, February 16, 2011

All You Need for JSONP

I have just uploaded a truly simple, still robust, function able to do generic JSONP without pretending too much magic.

The concept is simple, we pass the url, including the parameter name used to communicate the callback name, and a callback as second argument ... that's it, 202 216 bytes minified and gzipped ( many thanks @jdalton for the catch )

Here an example:

<!-- the generic HTML page -->
<script src="JSONP.js"></script>
<script>
this.onload = function () {
var many = 0;
JSONP("test.php?callback", function (a, b, c) {
this.document.body.innerHTML += [
a, b, ++many, c
].join(" ") + "<br />";
});
JSONP("test.php?callback", function (a, b, c) {
this.document.body.innerHTML += [
a, b, ++many, c
].join(" ") + "<br />";
});
};
</script>

And here the testable demo result that should work with every bloody damned browser.

What's on the server? Nothing more than this:

<?php
if (isset($_GET['callback'])) {
header('Content-Type: application/javascript');
exit($_GET['callback'].'.call(window, "Hello", "JSONP", "!!!")');
}
?>


Enjoy ;)

7 comments:

rasmusfl0e said...

I like the compactness of the code :)

Though - the response isn't standard JSONP (in the sense that you can pass multiple arguments)... it does open up some more possibilities.

Why not drop the "?callback" part from the path argument and put it inside the function instead? Noone would ever really need to name it anything else, no?

Andrea Giammarchi said...

you can create your ad hoc url string the way you need and prefer ... just remember to set the expected name for the callback property as last part of the query string .... example:


JSONP("http://whatever.com/?a=a&b=b&fn", callback);

All the function will do is to append the right unique callback at the end of the string, e.g.

http://whatever.com/?a=a&b=b&fn=__JSON__123

The reson I don't want to parse anything is that everybody out there could have different requirements about the query string for JSONP requestes, but for sure the server will always produce the output accordingly with the parameter sent as callback to call.

I hope you understood my point ;)

rasmusfl0e said...

Yes, of course! In hindsight that question was really silly :P

Will Alexander said...

very elegant. creating a unique alias for each request is quite clever!

Would global[src]= void 0; be appropriate to delete the

Andrea Giammarchi said...

it will simply be undefined ... but not removed. IE < 9 problem ... I don't really care but I may solve differently, assuming JSONP as variable is global ( right now it should be embeddable without polluting the global scope )

Brett said...

Excellent...

How about adding properties onto JSONP itself instead of creating __JSONP__ globals? (Maybe this disallows embeddable use, but you're already forced to make globals anyways.)

Also, accepting a node (or ID/selector string) as the second argument whose innerHTML gets set to the first argument's string response would be very convenient as a likely common use case.

Andrea Giammarchi said...

for everything you need ... wrap it and that's it :-)

The purpose of this function is to do one thing: JSONP

DOM or whatever automagic parser/feature can be wrapped around in a couple of lines.

the global part is annoying only for IE < 9 ... and I am not sure we should care at all but I may introduce a variant that should work without leaving stuff around even in IE < 9, stay tuned