catching exceptions while waiting for a promise in nodejs

Gal Bashan Source

I am writing a library in nodejs, that is wrapping another library. my code is something like this:

function wrapper(functionToWrap) {
    return function(param1, param2) {
        try {
             return functionToWrap(param1, param2);
        } catch(err) {
            console.log(err);
            throw err;
        } finally {
            finalizeWrapping();
        }
    }
}

the problem is that my finalizeWrapping function is a function that waits for promises that i collect (by placing some hooks before calling functionToWrap on some of the async apis it uses) to resolve, and only then acts, something like this:

function finalizeWrapping() {
    Promise.all(pendingPromises).then(function(values) {
        //finalize the wrapping
        console.log('all promises fulfilled!');
    });
}

the issue is that the error is thrown and node exits (this error should not be handled, since the wrapped function doesn't handle it) before all the promises are resolved and the then block is executed.

my question is: is there anything i can do to work around this, meaning throwing the error to the user appropriately and finish executing the then block, or do i have to change the way i hook the apis to be synchronous and not use a promise?

Thanks in advance to all the helpers :)

EDIT: an attempt to make my question clearer - functionToWrap is not my function, it is a function of a different library (and it can change - meaning i want my code to be able to wrap as many functions as possible). this function is allowed to use async apis (which i may be trying to monkeypatch), and basically it should have as least restrictions as possible - i want the user to be able to write any function and me being able to wrap it.

javascriptnode.jserror-handlingpromisethrow

Answers

answered 3 months ago HMR #1

Not sure if the following can help, you may not have enough reputation to comment although I think you can comment on your own question and it's answers.

const wrapper = functionToWrap => 
  function() {
      //special type to indicate failed call to functionToWrap
      const Fail = function(reason){this.reason=reason;};
      //does not matter how many argument. Assuming functionToWrap
      //  does not rely on "this". If it does then also pass the 
      //  object that functionToWrap is on and replace null with that object
      return Promise.resolve(Array.from(arguments))
      .then(
        //if functionToWrap is on an object pass it to wrapper
        // and replace null with that object
        args=>functionToWrap.apply(null,args)
      )
      .catch(
        //if functionToWrap throws an error or rejects we will catch it here
        //  and resolve with a special Fail type value
        err=>{
          console.log(err);
          return new Fail(err)          
        }
      ).then(
        //since promise cannot fail (its rejection is caught and resolves with Fail)
        //  this will always be called
        //finalize should return Promise.all... and maybe not use a shared
        //  variable called pendingPromises, global shared mutable variables in async 
        //  functions is asking for trouble
        result=>finalizeWrapping().then(
          ()=>
            //if functionToWrap rejected or thew the result will be a Fail type
            (result && result.constructor === Fail)
              ? Promise.reject(result.reason)//reject with the original error
              : result//resolve with the functionToWrap result
        )
      );
  }

comments powered by Disqus