展平承诺链并执行特定于错误的catch语句

时间:2016-09-11 18:26:38

标签: javascript error-handling promise try-catch es6-promise

作为嵌套的替代方案,我在履行承诺方面遇到了一些麻烦。

假设我想通过检索用户并使用其id来检索另一个表中的关联帖子来建立表连接。像这样。

User.get(uid)
.then(usr => {

   return Post.get(usr.id)
})
.then(posts => {
   //send posts or continue the promise chain
});

现在,只要我想执行特定于某个承诺的错误处理逻辑而不执行任何其他操作,就会出现问题。在我的示例中,如果数据库找不到具有该ID的用户,则会抛出错误,然后如果找不到给定外键的帖子,则也会抛出错误。我想做的是回复一条特定于错误的消息,例如“找不到用户”或“找不到给用户的帖子”等。

我试图这样做

User.get(uid)
.catch(e => {
   //This executes whenever a user is not found but the problem is that it also 
   //executes the following 'then' statement
})
.then(usr => {

   return Post.get(usr.id)
})
.then(posts => {
   //send posts or continue the promise chain
})
.catch(e => {
   //This should only execute when posts aren't found with the id
});

现在,无论错误如何,.then都会执行,因此之前的代码无效。

所以我考虑在catch语句之后删除所有.then语句,比如

User.get(uid)
.then(usr => {

   return Post.get(usr.id)
})
.then(posts => {
   //send posts or continue the promise chain
})
.catch(e => {
   //This executes whenever a user is not found but the problem is that it also 
   //executes the following 'then' statement
})
.catch(e => {
   //This should only execute when posts aren't found with the id
});

但是这不起作用,因为第一个.catch语句总是执行。

以同步的方式,这将是我的代码编写方式

try
{
   var user = getUser(id);


   try
   {
      var posts = getPosts(user.id);
   }
   catch(e)
   {
      //this executes only if posts aren't found
   }

}
catch (e)
{
   //this executes if the error originates from obtaining a user
}

1 个答案:

答案 0 :(得分:0)

问题的核心是:

  

我想做的是回复一条错误消息,例如“找不到用户”或“找不到给定用户的帖子”等。

两件事:

  • 可以使用其他属性扩充错误对象。
  • 你不仅限于捕捉 - 你也可以投掷/重新抛出。

有了这个,您可以(至少)以几种不同的方式解决问题:

可以写一个扁平链:

User.get(uid)
.catch(e => { // initial catch is simple
    e.userMessage = "problem finding user"; // add user message as a custom property 
    throw e; // rethrow the augmented e to ensure the rest of the success path is not executed
})
.then(usr => Post.get(usr.id))
.catch((e) => { // intermediate catch(es) follow this pattern
    if(!e.userMessage) {
        e.userMessage = "problem finding posts"; // add user message as a custom property 
    }
    throw e; // rethrow the augmented e to ensure the rest of the success path is not executed
})
.then(posts => send(posts))
.catch(e => { // terminal catch is a bit different
    console.log(e); // (optional) 
    if(e.userMessage) {
        display(e.userMessage);
    } else {
        display("problem sending pots"); 
    }
});

但是需要在每个阶段之间区分最新的错误,使得这种扁平模式略显麻烦。

它更简单,并且在承诺的精神范围内,而不是扁平化。相反,给每个阶段都有自己的“私人”捕获。在第一阶段之后,这意味着嵌套的捕获。

User.get(uid)
.catch(e => {
    e.userMessage = "problem finding user"; // add user message as a custom property
    throw e; // rethrow the augmented e to ensure the rest of the success path is not executed
})
.then(usr => Post.get(usr.id).catch(e => {
    e.userMessage = "problem finding posts"; // add user message as a custom property 
    throw e; // rethrow the augmented e to ensure the rest of the success path is not executed
}))
.then(posts => send(posts).catch(e => {
    e.userMessage = "problem sending pots"; // add user message as a custom property
    throw e; // rethrow the augmented e
}))
.catch(e => {
    console.log(e); // (optional) log the error with its .message and .userMessage
    display(e.userMessage);
});

无论哪种方式,都会为三种可能来源中的每一种产生错误提供自定义用户信息。