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);
comments powered by Disqus

Related Posts

Write Software for People, Not Computers

Throughout a normal day, I end up reading a lot of information about current issues in technology, and today is no different. There was a debate raging about whether or not high-level math was required for programmers that was sparked by this article by Sarah Mei Programming is not math . While it is an interesting topic, and, surprisingly, I mostly agree with Sarah on this issue, that is not the most important portion of her post.

Read More

Hover Effects in JavaScript?

One of the things that can be annoying when looking at someone else’s code is when a more complex technology is used to solve a problem that can be handled more simply with another method. An example of this is when you utilize JavaScript to implement a hover effect on some elements. I know of one scenario when you would need JavaScript to trigger a hover effect, and that would be when you want to trigger the hover effect with a touch event.

Read More

Window.Open Causes Browser Compatibilty Issues

One of the things that always annoys me as a web developer is when native browser functions that are accesible from JavaScript do not share the same function signature. One perfect example of this is the window.open function. When you are using non-Microsoft browsers such as Firefox and Chrome, you are able to make a call something like this window.open(url, 'window name', 'dimensions or other settings');. The window name parameter is important because it allows you to open multiple links in the same external window/tab.

Read More