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( url, hollaback [, context] ) -> Null
* - url (String): URL to data resource.
* - hollaback (Function): Function to call when data is successfully loaded,
* it receives one argument: the data.
* - context (Object): Context to invoke the hollaback function in.
*
* Load external data through a JSONP interface.
*
* ### Examples
*
* loadJSONP(
* 'http://www.gigpark.com/businesses/runlevel6.json',
* function(data) {
* console.log(data)
* }
* )
**/
var loadJSONP = (function loadJSONP_outer( window, document, undefined ) { var uuid, head, main_script
uuid = 0
head = document.head || document.getElementsByTagName( 'head' )[0]
main_script = document.createElement( 'script' )
main_script.type = 'text/javascript'
return function loadJSONP_inner( url, callback, context ) { var name, script
// INIT
name = '__jsonp_' + uuid++
if ( url.match(/\?/) )
url += '&callback=' + name
else
url += '?callback=' + name
// Create script
script = main_script.cloneNode()
script.src = url
// Setup handler
window[name] = function( data ) {
callback.call( ( context || window ), data )
head.removeChild( script )
script = null
delete window[name]
}
// Load JSON
head.appendChild( script )
}
})( window, document )
@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