the jQuery queue function

The problem

If you’ve ever written code with a lot of callbacks, for example in a ajax-intensive website, it might have looked like this:

function dothis {
// do something

someCallback( function() {
// do more
}); // etcetera
});

Maybe your code had even more levels of callbacks. This style of code is hard to understand, hard to change, hard to debug and hard to maintain.

Turning every callback into a seperate, named function is a step in the right direction, but the different pieces are still very dependent on each other.

Ex: To make a hover effect for two different pictures

<script  type='text/javascript'>
$(document).ready(function(){
	$(".button").hover(function() {
		$(this).attr("src","button-hover.png");
			}, function() {
		$(this).attr("src","button.png");
	});
});
</script

The solution using queue

One of the ways to write high quality code is to make your code loosely coupled. In the ideal situation, all callback functions are decoupled and don’t know each others existance. With jQuery’s queue function we can do exactly that. The code will look like this.

$(someElement).queue(dothis).queue(dothat);

function dothis(next) {
// do something

someCallback( function() {
next();
});
}

function dothat(next) {
// do more
next();
}

Now the functions are decoupled, so it’s very easy to understand each function seperately, it’s easy to replace a function and it’s easy to refactor the code. In the first line, you can also easily see in which order which functions are called.

This approach clearly had advantages, so what are the disadvantages? One (possibly the only one) is that you can’t easily pass parameters this way. You could store the parameters somewhere using jQuery’s data function or in a DOM data-* attribute.

Ex:

jQuery(function($) {
	/**
	 * On button click, fetch and render the feed
	 */
	$('#button').click(function() {
		$('#feeds').queue(getUrl).queue(getRss).queue(getMd5).queue(getTags);
	});

	/**
	 * Get the feed-url from a local JSON-file
	 * @param next
	 */
	function getUrl(next) {
		$.get('feeds.json', function(feed) {
			$('#feeds').attr('data-feed-url', feed.url);
			next();
		});
	}

	/**
	 * Get the RSS-feed with the Google Feed API
	 * @param next
	 */
	function getRss(next) {
		var feed = $('#feeds').attr('data-feed-url');
		var apikey = "ABQIAAAA-1ApaLEvR6NDNIyWFGKEYRQO7ssAPC1kOSPo312uC5iafqUFvBSkQ3Qt2re4PPUEKNR3PVt5d-6HkQ";
		var url = "https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q="+encodeURIComponent(feed)+"&num=1&key="+apikey+"&callback=?";
		$.getJSON(url, function(data) {
			var entry = data.responseData.feed.entries[0];
			console.log('entry', entry)
			$('#feeds').append($('<h4>').text("Last article of "+data.responseData.feed.title))
					.append($('<a>').attr('href', entry.link).text(entry.title))
					.append($('<p>').text(entry.publishedDate));
			next();
		});
	}

	/**
	 * Calculate the MD5-hash of the url server-side for the Delicious API
	 * @param next
	 */
	function getMd5(next) {
		var url = $('#feeds a').attr('href');
		$.get('md5.php?q='+encodeURIComponent(url), function(data) {
			$('#feeds a').attr('data-md5hash', data.md5);
			next();
		});
	}

	/**
	 * Fetch the tags attached to the url
	 * @param next
	 */
	function getTags(next) {
		var hash = $('#feeds a').attr('data-md5hash');
		var url = "http://feeds.delicious.com/v2/json/urlinfo/"+hash+"?callback=?";
		var tags = "";
		$.getJSON(url, function(data) {
			for(tag in data[0].top_tags) {
				tags += " &bull; "+tag;
			}
			$('#feeds').append($('<p>').html(tags));
			next();
		});
	}
});
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s