2

I have the following code, with some chained promises. I am trying to throw an error in an inner then that I expected to be caught by the outer catch, but it is not the current behavior:

User.getById(userId).then((user: any) => {
    if (user.email != email) {
        User.getByEmail(email).then((user: any) => {
                throw new OperationError("exists"));
        }).catch(StorageError, (err: any) => {
            user.email = email;
            return user.save();
        });
    } else {
        return user.save();
    }
}).then((user: any) => {
    return {
        ok: true,
        user: user
    };
}).catch(OperationError, (error: any) => {
    return {
        ok: false,
        message: error.message
    };
}).asCallback(reply);

How can I make the outer catch be targeted by the throw statement?

EDIT Updated code as Vohuman suggested.

User.getById(userId).then((user: any) => {
    finalUser = user;

    if (user.email != email) {
        return User.getByEmail(email);
    }
    else {
    //I would like for this response [1] to be used in [2]
        return Promise.resolve(user);
    }
}).then((user: any) => {
    throw new OperationError("Email already exists");
}).catch(StorageError, (error: any) => {

    finalUser.email = email;
    return finalUser.save();
}).then((user: any) => {
    //[2] here is where I would like the else statement to come 

    sendEmail(user.email, subject, content);
    return { ok: true, user: user };
}).catch(OperationError, (error: any) => {

    return { ok: false, message: error.message };
}).asCallback(reply);

How can I now, resolve the user in the first else statement without having it caught in the following then?

The idea is to send an email confirmation if the email does not exist in the database OR if the email is the same as the requesting account (resend email confirmation). If the email already exists, I would like to abort execution.

Manuel Reis
  • 574
  • 8
  • 29
  • 8
    You should `return` the `getByEmail` promise. – Ram Aug 29 '16 at 16:05
  • @Vohuman: thank you for your help. And how should I deal with the else statement that returns a valid response? If you need more info, I can work on a fiddle – Manuel Reis Aug 29 '16 at 16:40
  • Here's a js fiddle: https://jsfiddle.net/q5df3qmg/ – Manuel Reis Aug 29 '16 at 16:47
  • You are welcome! The `else` part is fine. The `then` method is called with the resolved value of `user.save`. Do you have any specific problem? – Ram Aug 29 '16 at 16:59
  • @Vohuman, yes, in that particular fiddle, after resolving the promise in the else statement it will immediately go to the then statement, which is not what I intend. – Manuel Reis Aug 29 '16 at 17:04
  • I did not understand what you are really trying to do well enough to create my own answer. Your question would be a lot clearer if you described the objective of your code rather than just your problem. You may just be able to put a `return` in front of `User.getByEmail(email)` though the code looks particularly messy. This code also looks like its subject to a race condition. – jfriend00 Aug 29 '16 at 17:25
  • @jfriend00 I have updated the code, perhaps it will be clearer now – Manuel Reis Aug 29 '16 at 17:29
  • 2
    And, what is the question about the new code? FYI, when you change your code like this, you completely change the question to a new question which is not the way things should be done here. – jfriend00 Aug 29 '16 at 17:31
  • @jfriend00 Thank you for the suggestion. The initial question was on how to get the the throw statement to reach the outer catch, to which vohuman suggested to return the `getByEmail` promise. From there, I wanted to do the statements described in the comments on the code, but resolving the user as I am doing will be caught by the next `then` statement, which is not the intended behavior. – Manuel Reis Aug 29 '16 at 17:39
  • Next time don't update your original code to a new set of code. You can ADD a new version of the code if you still have issues. As it is, you've completely invalidated the prior answers because you've completely changed your question. If I had provided a prior answer, I'd be pissed. If you want the best help, you need to describe (in words), step by step what you are trying to accomplish and put the info in your question, not in comments. Right now you are demonstrating the [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – jfriend00 Aug 29 '16 at 17:45
  • @jfriend00 I understand it now. I have edited the question in a way that does not affect previous answers – Manuel Reis Aug 29 '16 at 17:47
  • Please describe (with words in your question) what you are trying to accomplish. Right now, you are asking us how to fix a detail in flawed implementation. We'd much rather understand the overall problem and provide a much better implementation. That is the XY problem (asking about a problem with your solution rather than describing the overall problem to be solved) and we can't help you get the best overall solution this way. All we can do is patch up your messy solution. – jfriend00 Aug 29 '16 at 17:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/122129/discussion-between-manuel-reis-and-jfriend00). – Manuel Reis Aug 29 '16 at 17:53
  • Regarding the second question (which really should be a separate post), it sounds like a duplicate of [How do I access previous promise results in a .then() chain?](http://stackoverflow.com/q/28250680/1048572) – Bergi Aug 29 '16 at 18:01

2 Answers2

3

Your approach is totally fine, you only forgot one little return. Without it, the inner promise won't be awaited and rejections won't trigger the outer catch.

User.getById(userId).then((user: any) => {
    if (user.email != email) {
        return User.getByEmail(email).then((user: any) => {
//      ^^^^^^
            throw new OperationError("exists"));
        }).catch(StorageError, (err: any) => {
            user.email = email;
            return user.save();
        });
    } else {
        return user.save();
    }
}).then((user: any) => {
    return {
        ok: true,
        user: user
    };
}).catch(OperationError, (error: any) => {
    return {
        ok: false,
        message: error.message
    };
}).asCallback(reply);
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

I tried this code, but it got resolved instead of rejected

new Promise(r=>r('b').then(()=>Promise.reject('x'))).catch(err=>console.log({error}))

result:

Promise {<fulfilled>: 'b'}
Sh eldeeb
  • 1,589
  • 3
  • 18
  • 41