Friday, July 27, 2012

Solving JavaScript Async Issues the Easy Way, With Events

By now we all know that JavaScript is asyncronous and what that means, right?  If not the following code will help explain the concept in 30 seconds:

This code will run function a() then b(), even if the ajax request in a() has not yet completed.

There are a lot of approaches that can be used to make sure that b only runs when a is done.  One approach would be to use jQuery deferreds like so:

We can also use a async library, such as q, if we need a bit more power.  Or we can use JavaScript's setTimeout(func, delay) function to continuously check for a variable the function a() sets when it is done before we call b(), how awful does that sound? In some cases there is a quite simple way to achieve this, by using events.  I might even argue that using events is the more JavaScripty way to do things in the right situation.  Lets take a look at the a/b example, this time using events:

Lets take take a look at a real world example of using events to make sure things happen in the proper order.  Here we will use a backbone collection as a wrapper for a one or more Contact objects that will be reused in multiple places in an application:

Let say we want to use this collection to populate a drop down when a view is initialized like so:

Using this code there is a good chance that the models will be an empty array when we try to add them to the dropdown.  Also, when the collection's fetch() completes the app.contacts.models array will be reset, meaning that the reference to the contacts in your view likely will not reference the current app.contacts.models array.

To fix this, lets first update our collection to trigger an event when the contacts are loaded.  In this example I'm going to use jQuery's trigger(eventName) function to keep things easy:

The last step is to make sure we are adding the carriers to the drop down after they have been added to the collection. To do this we just need to add an event listener to our initialize function:

Now we will always be working with a populated collection in our addContacts method.
Fork me on GitHub