title: Async.eachSeries: Callback already called
body: <p>This is a little long and messy code, but please bear with me because I need to get this done.</p>
  
  <p>I am trying to update a json object in for each users. I want the loop iterations to wait for the asynchronous process to end in order to avoid race conditions. However, this has led to a callback hell and now I cannot decide what is the right place for each callbacks to be returned.</p>
  
  <p>I referred to this answer on Nesting <a href="https://stackoverflow.com/a/25712826/8515731">async.eachSeries</a> and also tried to structure my code according to it. But still it does not work. The code gives callback already called error at callback1().</p>
  
  <pre><code>    async.eachOfSeries(res, function (value, camp, callback3) {
  let _id = res[camp]._id;
  let arr = res[camp].campaignID;
  async.eachOfSeries(arr, function2, function (err) {
      callback3();
  })
  
  
  function function2(value1, i, callback2) {
      let users = arr[i].users;
      let id = arr[i].id;
      let loop = Math.ceil(users / 1000);
      let limit = 0,
          offset = 0;
      for (let j = 0; j &lt; loop; j++) {
          if (users &gt; 1000) {
              limit = 1000;
              users -= limit;
          } else {
              limit = users;
          }
          console.log(limit + " limit " + offset + " offset");
          var start = Date.now();
          while (Date.now() &lt; start + 100) {}
          const request = mailjet
              .get("messagesentstatistics")
              .request({
                  "CampaignID": id,
                  "AllMessages": true,
                  "Limit": limit,
                  "Offset": offset
              })
          request
              .then((result) =&gt; {
                  let data = result.body.Data;
                  var loop = 0;
                  async.eachOfSeries(data, function1, function (err) {
                      console.log("function");
                      callback2();
                  })
                  console.log("oooooo");
              })
              .catch((err) =&gt; {
                  console.log(err);
              })
          offset += limit;
      }
  
      function function1(value2, val, callback1) {
          console.log(data +" data");
          let jsonObj = data[val];
          let email = jsonObj.ToEmail;
          jsonObj['retailer'] = res[camp].retailer;
          jsonObj['summary'] = 'f';
          let tempObj = {};
          tempObj[id] = jsonObj;
          let options = {
              new: true
          };
          let campId = id;
          User.addCampaignResponse(email, campId, tempObj, options, function (err, results) {
              if (err) {
                  throw err;
              } else {
                  console.log("aasd");
                  Campaign.updateResponse(_id, function (err, results2) {
                      if (err)
                          throw err;
                      else {
                          console.log("asdasaadas");
                          callback1();
                      }
                  }) // console.log(results);
              }
          })
      }
  
  }
  
  }, function (err) {
      callback(undefined, "doneeeeee");
  })
  </code></pre>
  
  <p>Is there a better way than this? Can I use waterfall too somewhere? Can I change the callback positions to avoid the error?</p>
  
  <hr>
  
  <p><strong>EDIT: Simplified code</strong></p>
  
  <pre><code>function function2(value1, i, callback2) {
      // ...
      const request = mailjet
                      .get("messagesentstatistics")
                      .request({
                         // ...
                      });
      request
         .then((result) =&gt; {
            // ...
            async.eachOfSeries(data, function1, function (err) {
              callback2();
            });
          })
          .catch((err) =&gt; {
            // ...
          });
      }
  </code></pre>
  
  <hr>
  
  <pre><code>function function1(value2, val, callback1) {
    // ...
    User.addCampaignResponse(email, campId, tempObj, options, function (err, results) {
      if (err) {
        throw err;
      } else {
        Campaign.updateResponse(_id, function (err, results2) {
          if (err) throw err;
          else callback1();
        });
      }
    });
  }
  </code></pre>
  
  <hr>
  
  <pre><code>async.eachOfSeries(res, function (value, camp, callback3) {
      // ...
  
      async.eachOfSeries(arr, function2, function (err) {
        callback3();
      });
  
    },
    function (err) {
      callback(undefined, "doneeeeee");
    });
  </code></pre>