13

I have a function that does some operation using an array. I would like to reject it when the array is empty.

As an example

myArrayFunction(){
        return new Promise(function (resolve, reject) {
           var a = new Array();
           //some operation with a
           if(a.length > 0){
               resolve(a);
           }else{
               reject('Not found');
           }           
        };
}

When the reject operation happens I get the following error. Possibly unhandled Error: Not found

However I have the following catch when the call to myArrayFunction() is made.

handlers.getArray = function (request, reply) {
    myArrayFunction().then(
        function (a) {
            reply(a);
        }).catch(reply(hapi.error.notFound('No array')));
};

What would be the correct way to reject the promise, catch the rejection and respond to the client?

Thank you.

Juan
  • 806
  • 1
  • 8
  • 15

1 Answers1

18

.catch takes a function as parameter however, you are passing it something else. When you don't pass a function to catch, it will silently just fail to do anything. Stupid but that's what ES6 promises do.

Because the .catch is not doing anything, the rejection becomes unhandled and is reported to you.


Fix is to pass a function to .catch:

handlers.getArray = function (request, reply) {
    myArrayFunction().then(function (a) {
        reply(a);
    }).catch(function(e) {
        reply(hapi.error.notFound('No array')));
    });
};

Because you are using a catch all, the error isn't necessarily a No array error. I suggest you do this instead:

function myArrayFunction() {
    // new Promise anti-pattern here but the answer is too long already...
    return new Promise(function (resolve, reject) {
            var a = new Array();
            //some operation with a
            if (a.length > 0) {
                resolve(a);
            } else {
                reject(hapi.error.notFound('No array'));
            }
        };
    }
}

function NotFoundError(e) {
    return e.statusCode === 404;
}

handlers.getArray = function (request, reply) {
    myArrayFunction().then(function (a) {
        reply(a);
    }).catch(NotFoundError, function(e) {
        reply(e);
    });
};

Which can be further shortened to:

handlers.getArray = function (request, reply) {
    myArrayFunction().then(reply).catch(NotFoundError, reply);
};

Also note the difference between:

// Calls the method catch, with the function reply as an argument
.catch(reply)

And

// Calls the function reply, then passes the result of calling reply
// to the method .catch, NOT what you wanted.
.catch(reply(...))
Esailija
  • 138,174
  • 23
  • 272
  • 326
  • The fix was to pass a function to .catch as you suggested. The second option i.e. .catch(NotFoundError, reply); gives me the following error "A catch filter must be an error constructor or a filter function" – Juan Jun 03 '14 at 14:25
  • @juan did you implement NotFoundError – Esailija Jun 03 '14 at 14:34
  • Yes, I it was implemented. – Juan Jun 04 '14 at 11:18
  • handlers.getArray = function (request, reply) { var name = request.query.tableId; model.getArray(name) .then(function (dataArray) { reply.file(dataArray[0]); }) .catch(NotFoundError, function(e) { reply(e); }); }; function NotFoundError(e) { return e.statusCode === 404; } – Juan Jun 04 '14 at 13:57
  • @juan can `e` be null or undefined? – Esailija Jun 04 '14 at 15:56
  • No, I return a message 'No array found'. – Juan Jun 04 '14 at 16:37
  • I have a similar problem however I am attaching a proper catch. I tried catch(error => {}) and catch(function(e){}) - the rejection inside the promise is failing all the time with unhandled promise rejection and the rest of the code inside the promise is executed - this is really bad... – Moonwalker Jul 08 '15 at 16:12