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

Flatten out promise chain and execute error specific catch statements

本文关键字:错误 语句 catch 于错误 承诺 执行      更新时间:2023-09-26

我在将我的承诺作为嵌套的替代方案时遇到了一点麻烦。

假设我想通过检索用户并使用其id检索另一个表中的相关帖子来进行表连接。一样。

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

现在,每当我想执行特定于某个承诺的错误处理逻辑而不执行其他任何内容时,问题就出现了。在我的例子中,如果数据库没有找到具有该ID的用户,它会抛出一个错误,然后如果它没有通过给定的外键找到帖子,它也会抛出一个错误。我想做的是响应一个特定的错误消息,如"未找到用户"或"给定用户未找到帖子"等。

I tried to do this

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
}

问题的核心是:

我想做的是响应一个特定的错误消息,如"用户未找到"或"给定用户未找到帖子"等。

两件事:

  • 错误对象可以通过附加属性进行扩展。
  • 你不局限于接球-你也可以扔/再扔。
有了这些,您可以(至少)用几种不同的方法来解决问题:

可以写一个平链:

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);
});

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