Synchronous forEach loop (wait for it to end)

27,873

Solution 1

It is not a question of sync/async execution. What you are doing is returning true in the for each callback (which is invisible for your analyze_data function), then returning false after forEach is finished.

You need to use Array.prototype.some:

var analyze_data = function (data) {
    return data.some(function (elm) {
        return elm.myProp == true;
    });
}

Solution 2

Your problem is not the fact that forEach is async, because it is not. But because you mistake one return for another.

You return true from callback not from your main function.

forEach called forEach because it executes for each element on the array, you can't stop in the middle. Here is the excerpt from documentation:

Note: There is no way to stop or break a forEach loop. The solution is to use Array.every or Array.some.

Solution 3

The issue is that you are returning from your inner function the value of true, but not capturing it in the outer function. If you do it like this it should work:

var retVal = false;
data.forEach(function (elm) {
    if (elm.myProp == true) {
        retVal = true;
    }
});
return retVal;

Right now you have two functions:

var analyze_data = ***function (data)*** {
  data.forEach(***function (elm)*** {
    if (elm.myProp == true) {
        return true; //returns out of function(elm)
    }
  });
  //the true value is gone - you didn't do anything with it
  return false; //always returns false out of function(data)
}

EDIT:

data.forEach(function (elm) {
    if (elm.myProp == true) {
        resolve(elm);
    }
});
resolve(false);

You now are (possibly) resolving to elm, but ALWAYS after that resolving to false. I'm not 100% sure on the behaviour, but I would guess that the later one overwrites the first one. So again, you need to check:

is_found = false;
data.forEach(function (elm) {
    if (elm.myProp == true) {
        resolve(elm);
        is_found = true;
    }
});
if (!is_found) {
    resolve(false);
}

Of course, it kind of seems like you should be doing:

if (!is_found) {
   reject(false);
}

So then you can do:

promise.then(function(result) {
    // do stuff since it found stuff :)
}, function(err) {
    // do stuff since if didn't find anything :(
});
Share:
27,873
apparatix
Author by

apparatix

Updated on July 09, 2022

Comments

  • apparatix
    apparatix almost 2 years

    I have a function in Node.js that takes in an array and loops through it, doing somewhat time-consuming computations on each element.

    Here's a super-simplified version of the function:

    var analyze_data = function (data) {
        data.forEach(function (elm) {
            if (elm.myProp == true) {
                return true;
            }
        });
        return false;
    }
    

    Essentially, I want the function to return true if any of the elements' property myProp is equal to true. If none of the elements satisfy this condition, the function should return false.

    However, the code never waits for the forEach loop to finish. In other words, if the 100th element in the array satisfies the condition, the function should return true. Instead, it skips to return false; and returns false before the forEach loop has time to finish.

    Is there a solution to this?

    Edit

    So I realized that I oversimplified my question - I'm actually using the Node.js package es6-promise, and my code looks more like this:

    var analyze_data = function (data) {
        return new Promise(function (resolve, reject) {
            data.forEach(function (elm) {
                if (elm.myProp == true) {
                    resolve(elm);
                }
            });
            resolve(false);
        });
    }
    

    So in reality, I don't have the issue of returning a value in the forEach function rather than the outer function. Additionally, notice how the function resolves to the element itself rather than true, otherwise false. I actually want to return some relevant data if the one of the elements passes the condition, otherwise false to indicate that they all failed.

    Any ideas now? :p Also, thanks for all the original answers!