Handling Callbacks with a Depth-First Tree in JavaScript

One of the hardest things to do in JavaScript when working with complex data structures and a callback oriented platform is to know for sure when all of your callbacks have been fully executed. This issue came to light when working with a MongoDB datastore that was being used to store an infinitely-deep nested menu structure.

This menu structure could be visualized as being a tree. In order to get the all of the needed menu items from this tree, a depth-first traversal of the tree was determined to be the easiest to track. Since I typically try to write the least amount of code possible to solve a problem, I started out with a set of simple callbacks that worked perfectly as long as there was only one menu-item that had any children. As soon as I had multiple children to traverse, the timing of the execution of the final callback happened well before it should have as well as occurring again at the correct time, causing some unexpected results.

I am sure that there are many ways to solve this particular issue that have some elegant algorithmic roots, I am trying to use the simplest method possible. In fact, there is a library that was originally written for use with NodeJS the solves this exact issue. The async library allows you to use async.each(array, iterator, callback);, which will call the iterator function for each member of array, and the iterator function should handle any necessary processing, calling the callback function when complete. If any of the instances of iterator throw an error, the other instances are short-circuited. If they all run to completion, the callback function passed in will be called only when all have completed successfully, greatly simplifying the logic.

A simple example with Mongo and recursion would be:

function loadMenu(element, index, array, done) {
    menu.model.find().exec().then(function (menus) {
        //Do Stuff Here...
        async.each(menus, loadMenu, done);
    });
}

async.each(menu, loadMenu, done);

Related Posts

Oct 23, 2014
5 minutes

Do you have too many big balls?

Managing a software development team can be a difficult task when everything is moving along exactly as expected. When you add in the paradigm shift of Agile Software Development with Scrum, management doesn’t always have the same insights into what makes up an efficient use of a development team’s time. For the rest of this post, lets assume that we are working with a 2 week sprint, with the first day half-used for sprint planning, and the last day half used for the sprint retrospective.

Mar 17, 2015
2 minutes

When Is Enough CSS Enough?

One of the major pushes in web development today is to try to do as much of the styling of a website as is possible from within the CSS of the site. The idea behind this is that when you do so, you remove styling responsibilities from your JavaScript and HTML content, resulting in a much better separation of concerns. The other aspect of this is that CSS styling is typically handled in a more native fashion in the browser as compared to what you can accomplish via Javascript.

Mar 24, 2015
2 minutes

Laravel Removed The QuickStart For Version 5

To start out, I want to be clear that what follows should not be interpreted to be a criticism of the software framework that those that work on Laravel publish, nor an indictment of open-source software as a whole. Rather, it is a look at how some projects, open or closed source make it harder than it should be for new users/developers to utilize their terrific products.

It seems experts conveniently “forget” the tips and tricks and tribulations it takes to learn a new technology, covering it all with, “It’s just so easy”.