petkaantonov/bluebird

tapReflect() / observe state in finally()

cdhowie opened this issue · 0 comments

I have a use case where I always want to do something when a promise is settled, but with minor differences depending on whether the promise was fulfilled or rejected. However, I don't want to change the fate of the returned promise.

What I'm looking for is a combination of .finally() and .reflect(), where my handler is always called and can observe the state of the promise, but returning a promise with the same eventual state as the promise I invoke on (unless my handler returns a rejected promise, as usual).

My use case is sending a "task completed" notification to a message queue, regardless of whether the task succeeded or failed, but with contents indicating success or failure. However, the returned promise should remain fulfilled or rejected so the caller can naturally proceed depending on the result (without requiring the caller to understand the PromiseInspection object).

There's a few workarounds for this:

function theHandler(err, value) {
  // do some stuff
}

// Elsewhere
return somePromiseChain()
.tapCatch(theHandler)
.tap(value => theHandler(null, value));

Declaring the function out-of-band is a bit of an awkward maneuver to accomplish this.

Another option:

return somePromiseChain()
.reflect()
.then(pi => {
  // do some stuff

  return pi.isRejected() ? Promise.reject(pi.reason()) : Promise.resolve(pi.value());
})

This is a bit verbose... a wrapper function converting a PromiseInspection back into a Promise would help, but still feels like a hack.

I'm using this currently:

Promise.prototype.tapReflect = function (handler) {
  return this
  .reflect()
  .then(handler)
  .return(this);
};

It seems like this might be useful to others.