Kyle Banks

JavaScript Array 'Monkey-Patch' to Execute Functions Sequentially

Written by @kylewbanks on Dec 12, 2014.

Here's a monkey-patch for JavaScript Array objects that allows an array of functions to be executed sequentially; that is, one after another. At the end a callback function is executed with an array of Errors (or null if there were none), and an array of responses, which can contain anything you wish.

Let's take a look:

// Add the sequence function to the Array prototype
Array.prototype.sequence = function(cb) { 
   var self = this;
   var index = 0;
   
   var errors = [],
       responses = [];
      
   // Recursively call _next until the index reaches the length of this Array
   function _next(index) {
      if (index < self.length) {
         // There's a function to execute, run it...
         self[index](function(err, res) {
            if (err) 
               errors.push(err);
            if (res) 
               responses.push(res);
               
            // Increment the index, and execute the next function
            index ++;
            _next(index);
         });
      } else {
         // Reached the end of the array, execute the final callback
         cb (errors.length > 0 ? errors : null, responses);
      }
   }
   
   // Start it off
   _next(0);
};

The sequence function is pretty straightforward. First we call _next with an index of 0, in which we check if we have exceeded the length of the array. If so, we execute the final callback (passed to the sequence function). Otherwise, we execute the function at the current index, increment the index, and continue calling _next until we reach the end of the array.

Now let's see it in action:

[
   function(next) {
      console.log('Function 1');
      setTimeout(function() {
         console.log('... timeout complete.');
         next(null, true);
      }, 1000);
   },
   function(next) {
      console.log('Function 2');
      next(null, true);
   },
   function(next) {
      console.log('Function 3');
      next(new Error('Test Error'));
   }
].sequence(function(err, res) {
   console.log("----------------------");
   console.log("Done With Results:");
   console.log(err);
   console.log(res);
});

First up, define an array of functions that you want to execute. Each function must take a callback (called next in the examples above), and execute it upon completion. The callback takes two arguments, the first being an Error (or null), the second being any response you want to pass to the final callback.

Speaking of the final callback, we now call sequence on the array, and give it a callback to execute when all of the functions in the array have finished executing. The final callback will receive two arguments, which are an array of Errors and an array of arbitrary responses, which is the collective sum of all the callbacks you executed in the array of functions. In the example above, the output would look like so:

Function 1
... timeout complete.
Function 2
Function 3
----------------------
Done With Results:
[ [Error: Test Error] ]
[ true, true ]

Disclosure

Monkey-patches are a pretty hot topic: some developers avoid them like the plague, and others are all for them. I'm of the latter group, assuming you understand the implications of using them, and aren't just blindly copy-and-pasting all the patches you come across. They can be dangerous, and it's important to understand what the patch is doing before you add it to your codebase.

In addition, this is a pretty short and to-the-point implementation. It has worked for my needs, but may have pitfalls in certain use-cases. However, it should at the very least act as a good starting point, and can be easily customized to suit your needs.

Let me know if this post was helpful on Twitter @kylewbanks or down below, and follow me to keep up with future posts!