Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Is re-throwing in promises going to be supported by $q at some point? #13990

Closed
adamreisnz opened this issue Feb 10, 2016 · 10 comments
Closed

Is re-throwing in promises going to be supported by $q at some point? #13990

adamreisnz opened this issue Feb 10, 2016 · 10 comments

Comments

@adamreisnz
Copy link

The docs for $q state:

Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.

and

This also means that if you "catch" an error via a promise error callback and you want to forward the error to the promise derived from the current promise, you have to "rethrow" the error by returning a rejection constructed via reject

So my question is, is this planned to be supported at any time in Angular 1? In a successful .then chain we can keep returning the same item/data, or modify it and return that, so why not re-throw an error in .catch that occurred without needing to include $q as a dependency?

E.g.

doSomething
  .catch(error => {
    doSomethingElse();
    throw error;
  });

instead of:

doSomething
  .catch(error => {
    doSomethingElse();
    return $q.reject(error);
  });

If not, is there a specific reason for this not being supported in $q?

@gkalpak
Copy link
Member

gkalpak commented Feb 10, 2016

Throwing an error from within a .then or .catch callback does already work for rejecting the promise.

It seems like you have misinterpreted the quoted statements:

Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.

This only refers to the throwing from within the contructor (i.e. resolver function), when using $q as a constructor (ES6-style). E.g.:

$q(function (resolve, reject) {
  throw new Error('From constructor !');
}).then(
  // Will never get here unless you call `resolve()` or `reject()`.
  // Throwing won't work !
);

But it's OK, because when using $q like this, you can use the reject function argument, so no need for $q.reject().

This also means that if you "catch" an error via a promise error callback and you want to forward the error to the promise derived from the current promise, you have to "rethrow" the error by returning a rejection constructed via reject

The key word here is "forward". Throwing an error will still work for rejecting the promise, but it does not do a good job at forwarding the initial error, because the next rejection handler will get your thrown error as argument.
So, if you only care to propagate the rejection, throwing is enough. If you want to propagate the error (which could be anything from null, to an error message string, to a custom object), you need to use $q.reject().


Closing as it seems like what you are asking is already supported.
Feel free to reopen, if I missed something 😃

@gkalpak gkalpak closed this as completed Feb 10, 2016
@adamreisnz
Copy link
Author

@gkalpak thanks for the reply, I guess I misinterpreted the first paragraph indeed.

But, what I am interested in, is indeed the ability to rethrow anything, be it null, a string, or a custom object, and not necessarily an exception/error object.

This works for example in Ember's promise library, and can be quite handy.
So for example the following would work as expected.

doSomething
  .then(() => {
    throw 'foo';
  })
  .catch(reason => {
    console.log(reason); //foo
  });

Can I take from your reply that this use case is not supported and will not be supported by $q?

@gkalpak
Copy link
Member

gkalpak commented Feb 10, 2016

@adambuczynski, ooops, how did I miss that ? Obviously you can throw anything and it works as you expect it to. (I guess I'm too used to throwing only Error objects 😃)
It's just JavaScript :)

The only difference between is that return $q.reject(anything) will just pass anything down the chain, while throw anything will additionally pass anything to the $exceptionHandler. Other than that, both methods work the same.

Sorry for the confusion 😞

@adamreisnz
Copy link
Author

@gkalpak No worries, and thanks for the clarification. Now that you've mentioned that, I remember why I wasn't using throws. It's not that it wasn't working, it's that those rejections weren't silent as they were sent to the $exceptionHandler, which in my case was logging to console.

Is there a way to turn off that behaviour in $q, perhaps via a decorator? Or is it too deeply baked into Angular?

@gkalpak
Copy link
Member

gkalpak commented Feb 10, 2016

Unfortunately, you can only decorate $exceptionHandler globally (not just for $q).

@adamreisnz
Copy link
Author

Yeah I was thinking of decorating $q for this use case, not $exceptionHandler :)

@gkalpak
Copy link
Member

gkalpak commented Feb 11, 2016

There's no easy way to skip the call to $exceptionHandler (unless you implement your own $q 😛). It's hidden deeply inside Deferred, which is a private "class" available to $q iirc.

@adamreisnz
Copy link
Author

Alright, I'll stick to using $q.reject's. Do you know if this works differently in Angular 2? Does Angular 2 use native promises, or can you specify a promise library to use?

@gkalpak
Copy link
Member

gkalpak commented Feb 11, 2016

Angular 2 prefers Observables (not promises), but you can still use promises. Since ng2 uses zones, you can use native implementations and hooking in your library of choice should be fairly easy (although I haven't tried that).

But you'll probably want to use observables and not miss out on the new features the bring on the table 😁

@adamreisnz
Copy link
Author

Will give them a shot for sure, thank you.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants