Production Tear Down: How Does Flickr Handle Loading Scripts Asynchronously?
If you are using an async loader, or even if you are just putting your scripts at the bottom of your DOM, you have a problem. In some cases your scripts will load after the user has clicked on something that requires a JavaScript function to handle the click. It's possible you have a pure HTML version, but if the user has JavaScript we want them to use it, even if the JavaScript hasn't loaded yet. You need some way of handling events before all of your assets have finished loading.
There are a number of ways we could do this, but it's helpful to look at a working implementation. This is going to be a two part series. First, we are going to look at how Flickr does this. In the second part, we can take the code that Flickr uses and extract the main features so that anyone can use the code.
In all of the code that Flickr loads before the body this is the part that matters to us: Isolated actionQueue Code.
Let's walk through this. F
is the global Flickr object that contains all of Flickr's JavaScript. Not only is this a common pattern among frontend developers, this technique is widely taught, and accepted at Yahoo. By keeping all of your site's functionality in one global object you are not polluting the global namespace. It also is a great way to organize your code.
If a user is able to interact with the site before the scripts have finished loading, you still want to handle the user's click somehow. It may not need to be completely handled, but the interface should be responsive. Code may run in the time between when the click event is fired, and when the module that can handle the event is loaded. Finally, it should be possible to run code after everything has loaded.
Basically, there are two phases: interim and cleanup. Interim code will be the code run right away, as soon as the user clicks something. Cleanup code will be the code that gets run as soon as the rest of the code has finished loading. The Flickr code actually uses this terminology.
Flickr calls this module, that handles events before code is loaded, the actionQueue
. Given that we now understand the basics of how the actionQueue
works, the first step is to register a click_queue
handler. The fav button is a good demonstration of this.
In the un-faved state the star is black and white:
The active state is a colour star:
There are two things that need to happen when a person clicks on the favorite button.
- The button needs to change state to purple
- An Ajax call needs to be made register the state change
The visual state change is as simple as adding a class to the element. Very little code is required for that. On the other hand, the Ajax operation is going to require a lot more code. So, to use actionQueue
an action should be registered so that in the interim the visual state can be changed, and in the cleanup stage the Ajax operation will be performed.
The advantage of this approach is immediate feedback. Once the module has then the Ajax operation can be performed. And, this is exactly how Flickr implemented this functionality: Flickr actionQueue Fav Handler.
The register
function only handles potential actions, and not actions that have actually been triggered. That is what the queue_click
function is for.
The queue_click
function can be called when an actual event has happened. In the case of the fav button, this will be a click event.
Now, this is where things get awesome. I am a fan of killing sacred cows. One of those in the front-end community is to not use onclick
attributes, it's certainly become dogma for many. Clearly we can see Flickr doesn't care. I don't know the details of why Flickr is using onclick
, but I have to assume it's because it's the lowest common denominator, and it works.
Looking at the HTML for the button shows that the queue_click
function is just called from the onclick
handler. In turn the function will return false
if the page is still waiting for code to load, thus canceling the browser's default operation: Flickr Favorite Button.
And, that's it. In this manner Flickr is able to handle all of us who are able to click faster than JavaScript is able to load. After breaking down this technique I wondered if there might be an easier way to handle actions before they loaded.
Now that we have seen how Flickr handles this problem, how can we use the techniques in our own code? In part 2, I am going to explore Flickr's code in detail, and demonstrate how it can be used with any site.