22 3 / 2012

Deferring Google API

I just love jQuery Deferreds. There are so many things that can be greatly simplified with this concept.

Here is how we can write simple wrapper around google api to make it less painful to load and work with.

@GoogleAPI =
  dfd: null,

  load: ->
    script = document.createElement("script")
    script.src = "https://www.google.com/jsapi"
    script.src+= "?key=API-KEY"
    script.src+= "&callback=GoogleAPI.loading_complete"
    script.type = "text/javascript"
    document.getElementsByTagName("head")[0].appendChild(script)

  loading_complete: ->
    GoogleAPI.dfd.resolve()

  loaded: ->
    if !GoogleAPI.dfd
      GoogleAPI.dfd = $.Deferred()
      GoogleAPI.load()
    GoogleAPI.dfd.promise()

First time GoogleAPI.loaded method is called, it will return the promise object and start loading jsapi script by appending it to document head. Once the script is loaded, the promise will be resolved and the callback will fire.

The beauty of this is that you can use these promises anywhere you want regardless of whether jsapi is loaded, is loading, or is yet to load. As soon as its available, all callbacks will fire.

Another cool thing is that Google jsapi will never load if its not required by your code.

The usage is really simple. It goes something like this:

$.when(GoogleAPI.loaded()).then -> console.log("jsapi loaded!")

It really reads nice: when GoogleAPI is loaded, then do the dance :)

Whats even more cool is that we can stack such modules one on top of the another. This is how GoogleMaps module would look like:

@GoogleMaps =
  dfd: null,

  load: ->
    google.load 'maps', '3', 
      callback: GoogleMaps.loading_complete, 
      other_params: "sensor=false"

  loading_complete: ->
    GoogleMaps.dfd.resolve()

  loaded: ->
    if !GoogleMaps.dfd
      GoogleMaps.dfd = $.Deferred()
      $.when(GoogleAPI.loaded()).then -> GoogleMaps.load()
    GoogleMaps.dfd.promise()

This one will load GoogleAPI first, then maps package. Once both load, you’re good to go. Once again, usage is real candy:

$.when(GoogleMaps.loaded()).then -> console.log("maps loaded!")

We can now even create GoogleCharts module with similar implementation. The awesome thing is that it won’t reload GoogleAPI if GoogleMaps already loaded it.

It all just works, and it works nicely!