adelriosantiago adelriosantiago - 4 years ago 95
Javascript Question

Return after all "on" events are called inside a JS promise

In Node.js, using NodeGit. I'm using a function similar to this inside a POST Express.js route. This route should get the commits between endCommit and startCommit:

router.post('/getLog', function(req, res, next) {
var logData = [];

Git.Repository.open(path.join(repositories.mine.path))
.then(function(repo) {
return {
endCommit: [ First commit object ], //Just a random commit object that has a "sha" inside
startCommit: [ Second commit object ] //Just a random commit object that has a "sha" inside
};
})
.then(function(range) {
// History returns an event.

var history = range.endCommit.history(Git.Revwalk.SORT.Time);

// History emits "commit" event for each commit in the branch's history
history.on("commit", function(commit) {
logData.push({
commit: commit.sha(),
message: commit.message()
});

if (commit.sha() == range.startCommit.sha()) {
console.log("---LOG CREATED---");
history.end();
}
})

history.start();
})
.done(function() {
console.log("---RETURNING---");

return res.json({ logData: logData });
});
});


However, since
history.on("commit", ...)
is not a Promise the
.done()
function is called first. In the log I see:

---RETURNING---
---LOG CREATED---


How can I return only after the log has been created?

I've came across issues like this in the past however in this particular case I don't know how could I promisify the history object because it is based on events.

Answer Source

You can wrap event handling in a promise that should be resolved once you are done, and return it:

.then(function(range) {
  // History returns an event.

  var history = range.endCommit.history(Git.Revwalk.SORT.Time);

  var commitPromise = new Promise(function(resolve, reject) {
    // History emits "commit" event for each commit in the branch's history
    history.on("commit", function(commit) {
      logData.push({
        commit: commit.sha(),
        message: commit.message()
      });

      if (commit.sha() == range.startCommit.sha()) {
        console.log("---LOG CREATED---");
        history.end();

        // resolve the promise
        resolve();
      }
    })
  });

  history.start();

  return commitPromise;
})

I assume you have Promise global. It's up to you choosing particular promise implementation - you may want to use bluebird for example.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download