0

Is forEach on an array async ? candies is an array of candy objects.

app.get('/api/:id',function(req, res){

  console.log("Get candy");
  var id = req.params.id;

  candies.forEach( function(candy, index){
    if(candy.id == id){
      console.log("Candy found. Before return");
      return res.json(candy);
      console.log("Candy found. After return");
    }
  });

  console.log("Print error message");
  return res.json({error: "Candy not found"});
});

In the console I get

[nodemon] starting `node app.js`
listning on port 3000
Get candy
Candy found. Before return
Print error message
Error: Can't set headers after they are sent.
   at ServerResponse.setHeader (_http_outgoing.js:367:11)
   ....

Is this a recent change ? It's been awhile since I have done node.js

4
  • 3
    Why do you have code after a return? Commented Feb 28, 2017 at 9:26
  • If it were async, you'd have Print error message logged first. Why would it be async? Also, Thilo pointed out correctly - what's the point of code after return statement? That will never be executed. Commented Feb 28, 2017 at 9:27
  • 1
    Also, the return in the inner function will only exit the inner function, not the outer one. Commented Feb 28, 2017 at 9:27
  • Ahh there we go.. Of course! Perfect that explains it. I must not be thinking straight today. Thanks @Thilo ! Commented Feb 28, 2017 at 11:42

2 Answers 2

1

You're getting the Can't set headers after they are sent. exception because you're trying to return a response twice - (possibly) once inside candies.forEach and once again in the last line of the route. Also note that any code after a return isn't executed anyways.

Here's how you rewrite it to avoid the error —

app.get('/api/:id',function(req, res){

    console.log("Get candy");
    var id = req.params.id;
    var foundCandy = false;
    candies.forEach( function(candy, index){
        if(candy.id == id){
            foundCandy = true;
            console.log("Candy found. Before return");
        }
    });

    if (foundCandy) {
        return res.json(candy);
    } else {
        return res.json({error: "Candy not found"});
    }
});
Sign up to request clarification or add additional context in comments.

3 Comments

@Jens Using Array.filter like @Vladu Ionut's response here also leads to cleaner & more concise code.
Thanks! I know how to solve it. I am just curious as to why I am getting this behavior. Both res.json(candy) and res.json({error: "Candy not found"}); get's called. That does not seem logical to me unless forEach is now an async function
Got it... See @Thilo reply
1

You can use Array.filter to find the candy .

app.get('/api/:id', function(req, res) {

  console.log("Get candy");
  var id = req.params.id;

  var result = candies.filter(candy => candy.id == id);

  if (result.length) {
    return res.json(result[0]);
  } else {
    console.log("Print error message");
    return res.json({
      error: "Candy not found"
    });
  }
});

1 Comment

To anyone else looking at this question: The "return res.json(candy);" Only returns from the inner function defined in the forEach argument, it does not return from the entire function. There for both responses get called.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.