Search code examples
node.jspromisebluebird

Promise looping over nested arrays


I'm wrestling with nested promise loops and having trouble finding a working solution.

I looked around and found this: https://stackoverflow.com/a/29396005/3560729

The promiseWhile function seems to have what I need but I'm having trouble getting the nesting to return to the outer loop

promiseWhile:

function promiseWhile(predicate, action) {
    function loop() {
    if (!predicate()) return;
        return Promise.resolve(action()).then(loop);
    }
    return Promise.resolve().then(loop);
}

Nested Loop:

    let outerArray = outerArrayOfObjects;
    let returnArray = [];
    let returnArrayIndex = 0;
    let outerIndex = 0;
    let outerLength = outerArray.length;
    let passObject = { }; 

    promiseWhile(function() {
        return outerIndex < outerLength;
    }, function() {
        let innerIndex = 0;
        let innerLength = outerArray[outerIndex].innerArray.length;

        passObject = {
            innerObject: outerArray[outerIndex].innerArray[innerIndex],
            returnArray: returnArray,
            returnArrayIndex: returnArrayIndex
        };
        promiseWhile(function() {
            return innerIndex < innerLength;
        }, function() {
            return new Promise(function(resolve, reject){
                Promise.all([
                    promiseFunction1(innerObject),
                    promiseFunction2(innerObject),
                    promiseFunction3(innerObject),
                ])
                    .then(function (allMappings) {
                        passObject.returnArray[returnArrayIndex++] = {
                            "result1": allMappings[0],
                            "result2": allMappings[1],
                            "result3": allMappings[2]
                        }
                        offersIndex++;
                        return resolve(passObject)
                    })
                    .catch(function (err) {
                        offersIndex++;
                        return reject(err);
                    })
            })
        })
        outerIndex++;
      }).then(function() {
        return resolve(passObject);
      });
      })
      }

I think my main questions are: Where do I process the results? How should I pass the values such that the return array is built properly?


Solution

  • The promiseWhile above is good for performing actions but not good for setting values in a nested loop and returning the results.

    I ended up going with an approach using bluebird:

            var Promise = require('bluebird');
            let outerArray = object.outerArray;
            let returnArray = [];
            let returnIndex = 0;
            Promise.map(outerArray, function (outerArrayObject) {
                let innerArray = outerArrayObject.innerArray;
                let outerArrayValue = outerArrayObject.value;
    
                Promise.map(innerArray, function (innerArrayObject) {
    
                    Promise.all([
                        PromiseFunction1(innerArrayObject),
                        PromiseFunction2(innerArrayObject),
                        PromiseFunction3(innerArrayObject),
                    ])
                        .then(function (allResults) {
                            returnArray[returnIndex++] = {
                                "result1": allResults[0],
                                "result2": allResults[1],
                                "result3": allResults[2],
                                "result4": outerArrayValue,
                            }
                            return resolve(returnArray);
                        })
                        .catch(function (err) {
                            return reject(err);
                        })
                })
            })
                .then(function () {
                        return resolve(returnArray)
                    }
                ).catch(function(err){
                        return reject(err);
                    }
                )
            }