0

i have a weird situation i would like to know how to solve. in my app errors that happen after functions with promises do net get thrown and the app just stalls.

here an example:

getTenant = (req) ->
  deferred = Q.defer()

  deferred.resolve('foo') if req.info.referrer
  deferred.resolve('bar') if !req.info.referrer

  deferred.promise

Routes =[
  {
    method: 'GET'
    path:   '/'
    handler: (request, reply) ->
      getTenant(request).then (tenant) ->
        console.log 'tenant', tenant

        # here `User` is not defined and doesn't even exist
        # why is there no error here?

        if !User.isAuthorized(request, tenant)
          reply 'not authorized'
        else
          reply 'authorized' 

  }
]

after getTenant i call a function on User.
User doesn't exist or is imported but the app gives me no error.
why is that?
of course if i wrap the code in a try/catch i catch the error but thats not the point. i would expect the code to actually break and throw the error.

here the full sample app: https://github.com/aschmid/hapierrortest

thank you, andreas

aschmid00
  • 7,038
  • 2
  • 47
  • 66

2 Answers2

1

The short answer is because you have neglected to include your error handler. Promises always require both success and error handling functions.

This is a fundamental (and generally good) aspect of promises. Inside a promise handler (success or error), any thrown errors do not hit the window. Instead, the promise implementation internally wraps promise handlers in a try block, and upon capture, rejects the promise returned by .then. Why? So that you can choose where and when and how to deal with errors. This is why you can put a single catch(errHandler) (which is sugar for .then(null, errHandler)) at the end of a long promise chain:

somePromise.then(function s1 (val1){
  // use val1, return something (e.g. a new promise)
}).then(function s2 (val2){
  // use val2, return something (e.g. a new promise)
}).then(function s3 (val3){
  // use val3, return something (e.g. a new promise)
}).catch(function e1 (err1){
  // handle e1 as you like (console.log, render something on the UI, etc.)
});

In the above chain, an error that occurs at somePromise, s1, s2, or s3 will be handled at e1. This is pretty nice, better than having to handle the potential error explicitly at every step of the chain. You still CAN handle the error at every step if you want, but it's not at all necessary.

Generally with promises you'll handle the error in some way, you don't WANT errors to crash your app after all. But if for some reason you wanted errors to be re-thrown out to the outer scope, you'd have to use a promise library with a final method that allows for re-throwing. For example, .done() in the Q library.

Gabriel L.
  • 1,629
  • 1
  • 17
  • 18
  • i see. but what i don't really get is that the promise is already resolved so why would this still be part of the promise? – aschmid00 Jun 14 '15 at 17:08
  • The first part of the chain (the original promise) is resolved. So you hit the next available success handler (`.then(successHandler)`). However, *inside* that handler, you throw an error. So the next part of the chain is a rejected promise, which you have to handle with an error handler (either `.then(null, errorHandler)` or `.catch(errorHandler)`). Remember, every `.then` returns a NEW promise, so you can keep chaining results. Errors inside of handlers must be caught further down the chain. – Gabriel L. Jun 14 '15 at 17:27
  • ok i tested it and you are right. that given i think ill switch my function to callbacks because this promise behavior involves to many enclosures in my code which is something i want to avoid. thank you – aschmid00 Jun 15 '15 at 15:42
-1

I'll start by saying that I've never used Hapi, but the syntax you have looks fine EXCEPT...

If req.info is null, you'd get an exception thrown. Try this

deferred.resolve('foo') if req.info && req.info.referrer
deferred.resolve('bar') if !req.info || !req.info.referrer
Jeff Fairley
  • 8,071
  • 7
  • 46
  • 55
  • i appreciate your answer but the issue is not where you are. the promise gets resolve correctly. the error i would like to see is a `ReferenceError` because `User` is not defined. and this after the promise got resolved – aschmid00 Jun 12 '15 at 16:58
  • Oh, I see what you're saying. I guess I got lost in the coffee syntax. Without knowing more about how promises work in Hapi, I'll leave this up to someone else to answer. – Jeff Fairley Jun 12 '15 at 17:01