I have a large amount of static/rarely changing data in JSON format. To improve my ASP.NET MVC application performance, I would like to move them to a CDN (Amazon Cloud Front).
In the docs for $.getJSON
and $.ajax, the jsonp section notes that you can set the callback function name explicitly with the jsonpCallback
config property. So if you want JsonWrapping(...)
to be the function jquery expects inside of the jsonp response, you can tie things back up like so:
$.ajax({
url: 'http://blah.com/blah.json',
dataType: 'jsonp',
cache: true,
jsonpCallback: 'JsonWrapping'
})
.done(function(r) {
status.text('It worked.');
})
.fail(function (a, b, c) {
status.text('It failed.');
});
In the above example the expected callback function inside the jsonp response is now JsonWrapping()
, which jQuery will emit for you, respond to by calling .done()
above, and cleanup after itself - much cleaner than hard-coding JsonWrapping
into the page.
An important thing to consider is if you plan to have many jsonp calls on a single page, and your jsonp wrapping functions are hard-coded in the jsonp files, you should at least vary your wrapping function by something, like filename. Otherwise you create an asynchrony problem. For example assume you had this code:
function jsonp(url) {
return $.ajax({
url: url,
dataType: 'jsonp'
cache: true,
jsonpCallback: 'JsonWrapping'
});
}
jsonp('http://cdn.mine/one.jsonp')
.done(...);
jsonp('http://cdn.mine/two.jsonp')
.done(...);
One of these jsonp calls is going to finish before the other - it's impossible to know which - and jQuery is in an impossible situation where it can't know which .done()
to call for which response. As a result you'll get some page loads where they're called correctly, and some where the data crisscrosses. The solution is to vary by something like filename, like:
function jsonp(url, wrapper) {
return $.ajax({
url: url,
dataType: 'jsonp'
cache: true,
jsonpCallback: wrapper
});
}
jsonp('http://cdn.mine/one.jsonp', 'one')
.done(...);
jsonp('http://cdn.mine/two.jsonp', 'two')
.done(...);
So the response from two.jsonp would need to look like:
two({...json object here...})
The call at the beginning of this answer will make jQuery request the URL via GET like this:
http://blah.com/blah.json?callback=JsonWrapping
And expect this as the response:
JsonWrapping({...object here...})
I included cache: true
above because this is on a CDN, and so, presumably is not meant to change very often. If you leave cache: true
out, jQuery inserts a second querystring param meant for cache-busting, like:
http://blah.com/blah.json?callback=JsonWrapping&_=1365175172440
Which can ruin the point of a CDN. The goal of the second querystring parameter is to ensure the data isn't loaded from the browser cache, and, when it hits the server (the CDN in this case), the querystring is unique meaning it busts its cache as well.
Outside your scenario where you're using a CDN, there are situations where jQuery's default functionality is desirable: For example, when you want to simulate POST functionality across to another domain, without violating Same-Origin policy, jsonp with this cache busting feature can get that done for you.
If the server you're talking to expects something other than "callback" in the querystring for specifying the name of the callback function in the response, you can use the jsonp
config property - for example jsonp: 'myname'
would get you:
http://blah.com/blah.json?myname=JsonWrapping
I just found out this is somehow possible. I solved it like so:
$(document).ready(function(){
$.getJSON("http://example.com/staticjsonfile.json",function(data){
//callback function isn't here
}
});
function JsonWrapping(data){
//It's really here
alert(data);
}
This is not ideal, as you loose binding with the event that fired the Ajax request. So some hacking is required. However, it kinda gets the job done. I'd be very open to a better solution.