Skip to content

Instantly share code, notes, and snippets.

@gf3
Created June 18, 2009 18:18
Show Gist options
  • Save gf3/132080 to your computer and use it in GitHub Desktop.
Save gf3/132080 to your computer and use it in GitHub Desktop.
Simple JSONP in vanilla JS
/*
loadJSONP(
'http://www.gigpark.com/businesses/runlevel6.json',
function(data) {
console.log(data);
}
);
*/
var loadJSONP = (function(){
var unique = 0;
return function(url, callback, context) {
// INIT
var name = "_jsonp_" + unique++;
if (url.match(/\?/)) url += "&callback="+name;
else url += "?callback="+name;
// Create script
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// Setup handler
window[name] = function(data){
callback.call((context || window), data);
document.getElementsByTagName('head')[0].removeChild(script);
script = null;
delete window[name];
};
// Load JSON
document.getElementsByTagName('head')[0].appendChild(script);
};
})();
@DrStrangeLove
Copy link

Great gist!!
But what if some server script accepts different parameter instead of callback??
it could be http://xxx.yyy/script?jsonp=callbackname

@gf3
Copy link
Author

gf3 commented Sep 27, 2011

@DrStrangeLove It wouldn't be difficult to add a third argument, such as an options object. It could be used to control the name of the callback parameter.

@ManasJayanth
Copy link

@gf3 In line 28 I faced issues when name started with a double underscore. I had to use jsonp_ as the prefix (non underscore prefix)

@jimmywarting
Copy link

jimmywarting commented May 1, 2017

I modified it a bit to act little bit more like the new fetch api and using promises

 const fetchJSONP = (unique => url => 
   new Promise(rs => {
     // INIT
     let script = document.createElement('script')
     let name = "_jsonp_" + unique++
     
     if (url.match(/\?/)) url += "&callback="+name
     else url += "?callback="+name
     
     script.src = url
     window[name] = json => {
       rs(new Response(JSON.stringify(json)))
       script.remove()
       delete window[name]
     }
     
     document.body.appendChild(script)
   })
 )(0)

@michaelpumo
Copy link

@jimmywarting

More es2015 friendly and ESLinted according to AirBnb:

const fetchJSONP = (unique => url =>
  new Promise(rs => {
    const script = document.createElement('script');
    const name = `_jsonp_${unique++}`;

    if (url.match(/\?/)) {
      url += `&callback=${name}`;
    } else {
      url += `?callback=${name}`;
    }

    script.src = url;
    window[name] = json => {
      rs(new Response(JSON.stringify(json)));
      script.remove();
      delete window[name];
    };

    document.body.appendChild(script);
  })
)(0);

👍

Copy link

ghost commented Mar 5, 2018

can someone explain how it's works? because i have no idea.

@janbalaz
Copy link

Thanks for the code, it's good, but I wouldn't recommend using simple incrementation of counter to achieve unique callback name. I suggest using timestamp or random number. Although this code cleans up afterwards, when I used it twice in 2 widgets on the same site, there were collisions.
I used this solution:
https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment