1

I'm using the Gmail API to retrieve messages in a loop and do a req.write() for each message. There's a callback for each api invocation, but how do I know when the whole set is done so I can end the response? I tried the following but noticed that the callbacks are not executed in order of array index so I can't just do the line I commented out.

for (var i = 0; i < messages.length; i++) {
            var message = messages[i];
            console.log('- %s', message.id);
            (function(e){
              var request = gmail.users.messages.get({
                  auth:auth,
                  id:message.id,
                  userId: 'me'
                }, function(err, response) {
                  if(err) {
                    console.log('API returned an error: ' +err);
                    return;
                  }
                  res.write(JSON.stringify(response,null,'\t'));
                  console.log(e);
                  //if(e==messages.length-1) res.end();
                }
              );
            })(i);
}
andrewg
  • 175
  • 6
  • Solutions [here](http://stackoverflow.com/questions/32799672/node-js-how-to-set-a-variable-outside-the-current-scope/32799727#32799727) and [here](http://stackoverflow.com/questions/32871543/order-of-execution-issue-javascript/32872009#32872009). – jfriend00 Oct 03 '15 at 06:47

1 Answers1

2

You're on the right track, though. Since you won't get any callbacks until your loop is completed, you can just keep track of how many callbacks you've gotten and when it reaches messages.length, you know you're done:

var completed = 0;
for (var i = 0; i < messages.length; i++) {
    var message = messages[i];
    console.log('- %s', message.id);
    var request = gmail.users.messages.get({
        auth: auth,
        id: message.id,
        userId: 'me'
    }, function(err, response) {
        if (err) {
            // Should increment and check `completed` here too,
            // not sure what you want to do though
            console.log('API returned an error: ' + err);
            return;
        }
        res.write(JSON.stringify(response, null, '\t'));
        if (++completed == messages.length) {
            res.end();
        }
    });
}

That assumes nothing will change messages in the meantime (affecting its length). If that assumption isn't valid, you can just invert completed, call it pending, and you're done when it reaches 0:

var pending = 0;
for (var i = 0; i < messages.length; i++) {
    var message = messages[i];
    console.log('- %s', message.id);
    var request = gmail.users.messages.get({
        auth: auth,
        id: message.id,
        userId: 'me'
    }, function(err, response) {
        if (err) {
            // Should decrement and check `pending` here too,
            // not sure what you want to do though
            console.log('API returned an error: ' + err);
            return;
        }
        res.write(JSON.stringify(response, null, '\t'));
        if (--pending === 0) {
            res.end();
        }
    });
    ++pending;
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875