# Recursion to the Rescue in Asynchronous JavaScript

### This article is one attempt to simplify callbacks that are called within loops (such as for-loop or while-loop). Read on and see how it's done.

Join the DZone community and get the full member experience.

Join For Free## Callbacks Within Loops

While callbacks provide the ability to serialize execution of code, which is sometimes required in an asynchronous framework that JavaScript offers (e.g. Node.js), they can also very easily become daunting. Throw in a loop (such as for-loop or a while-loop) within the callback hell and now it’s a completely elevated level of complexity.

There are already a lot of alternatives to simplify the callback hell. One popular solution is the use of Promises. There are also some good discussions on this topic on Quora.

This article is one attempt to simplify callbacks that are called within loops (such as for-loop or while-loop). The problem, in this case specifically, is that if an asynchronous function is called within the loop, each iteration is executed asynchronously. Now, if further processing is required after the **entire** loop is executed, it becomes difficult to track the last iteration. Why? Because, what if although the last iteration is complete and the one before the last takes longer to return? Obviously, just tracking the last iteration is not good enough!

Before we look at how we can use recursion in this situation as one possible alternative, let’s take a quick dive into Recursion.

## A Little Bit About Recursion

Divide and conquer is perhaps the most common type of algorithm used to solve complex programming problems with optimal efficiency. Recursion is one method under the divide and conquer algorithms. Recursion really reduces a large problem into smaller simpler problems and the idea is that solving each small unit will eventually lead to the solving of the larger original problem. Recursion is achieved by writing *recursive functions*, which we will take a look at in a minute.

### Recursive Functions (Quick Refresher)

To put it simply, a recursive function is one that calls itself and looks for whether a base condition has been reached or not. If not, the problem is chopped down further by calling itself again. Let’s look at an example. In this example, we are going to add numbers between 1 and 10.**Hint:** Recursion involves a base case which is the last case in recursive function after which the recursion is complete and the problem has been solved.

```
var add = function(n, sum) {
if(n<1) {
return sum;
}// base case
else {
sum = sum + n;
n--;
return add(n, sum); // recursive call
} // chop down problem further
}
// calling recursive function
var result = 0; // this is where the final result will be stored
result = add(10,result); // call recursive function
```

Just take a few minutes to look at where we applied the “divide” from divide and conquer.

So here, we divided the larger problem of adding all numbers between 1 and 10 into the smaller problem of performing only one ‘addition’ operation per function call, meanwhile decrementing the number to be added by 1 before it was passed as a parameter to the subsequent function call.

Similarly, at the start of each function call, we determined whether the exit condition was reached, i.e. whether the number in question to be added was less than 1 or not. When the exit condition was reached, we simply returned the result, i.e. sum, back to the main program.

Now, let’s get back to the solution of the asynchronous loop problem.

## The Solution via Recursion

Assume we have a requirement similar to pricing a shopping cart. When a product is added to the shopping cart, we need to do the following for each product in the cart:

- Check if the product and quantity is eligible for a promotion. If eligible, price it accordingly, or else price as usual.
- When all products are priced, calculate the total.
- Calculate the tax based on the total.
- Finally, calculate the total cost of the shopping cart.

Below is the high-level code for achieving the above steps using recursion and callbacks. As mentioned earlier, the challenge is that steps 1 and 2 are performed for each product in the pricing cart; however, steps 3 and 4 are computed on the results from steps 1 and 2.

```
var calculatePrice = function(productid, quantity, callback){
// ... check promotion eligibility
callback(calculated_price);
}
var calculateTotal = function(total, productid, quantity, finalcallback, callback){
// ...
calculatePrice (productid, quantity, function(price){
total = total + price;
callback(total, finalcallback);
});
}
var calculateTax = function(total, tax_rate){
return (total + (total * tax_rate));
}
// And here is the recursive function
function forEachProductInCart(cartIndex, shoppingCart, total, callback){
if(cartIndex < 0) {
callback(total);
} // base case
else {
calculateTotal(total, shoppingCart[cartIndex].productid, shoppingCart[cartIndex].quantity, callback, function(total, callback){
cartIndex--;
forEachProductInCart(cartIndex, shoppingCart, total, callback);
})
}
} // forEachProductInCart: recursive function
/* .....................................................
And we call it here
..................................................... */
// var shoppingCart = [];
// shoppingCart contains all products added to the shopping cart
var subtotal = 0; // initial total cost
var finalTotal = 0; // initial final cost
var cartIndex = shoppingCart.length - 1;
// We call the recursive function here
forEachProductInCart(cartIndex, shoppingCart, subtotal, function(total){
var final_with_tax = calculateTax(total, 0.75); // final with tax
});
```

## Conclusion

JavaScript provides a solid asynchronous framework to build highly complex web applications already. It also provides the ability to create synchronous execution logic via "callbacks". Add them up with algorithms like recursions and you now have the ability to solve any complex computing requirement.

**Please feel free to comment, provide feedback, or tell me to add something if anything obvious was missed or if any additional perspective needs to be covered.**

Published at DZone with permission of mario pissardo. See the original article here.

Opinions expressed by DZone contributors are their own.

Comments