2015-09-25 74 views
1

背景的允许传播JS承诺:错误

比方说,我与+的NodeJS工作快。我在Express中注册了一些错误处理程序,它将以适当的方式处理我的应用程序中可能出现的所有错误。

因此,我可以把我的应用程序错误时,我必须这样做。如果有未处理的错误,我让它传播,直到它到达一个错误处理程序。然而,在尝试在承诺链内部抛出错误时,我遇到了一个问题。看看下面的例子:

function find() { 
    // consider this to be a promise from a library such as Bluebird 
    return new Promise(function (resolve, reject) { 
     // ... logic ... 
    }); 
} 

function controller (req, res) { 

    // ... omitted ... 

    find().then(function (result)) { 
     if (result) { 
      // let 'res' be the Express response object 
      res.send("It exists!"); 
     } else { 
      // let SpecificError be a prototypical subclass of Error 
      throw new SpecificError("Couldn't find it."); 
     } 
    }).catch(function (error) { 
     // throw the error again, so that the error handler can finish 
     // the job 
     throw error; 
    }); 
} 

虽然我一直在期待,我再扔最终至少击中一般错误处理程序中的错误,我也看不到我发送给我的应用程序挂起的请求,以及我正在使用的承诺库抱怨Unhandled rejection

问题

很简单,我想知道怎么解决,我似乎是处理不当,我在我的诺言链抛出一个错误创建拒绝的事实。

编辑:为澄清什么(具体)的错误处理程序和controller功能的,看下面的评论。

+0

什么是你期望它命中的“通用错误处理程序”?如果'controller'是一个路由,你应该使用第三个'next'参数并执行'next(error)' – loganfsmyth

+0

我想你会看到我想要做的事情 - 'next(error)'听起来像是正确的回答 – nmagerko

+0

如果你显示你如何调用controller(),我们会更好地了解你在做什么以及哪些选项最有意义。 – jfriend00

回答

3

假设你已经绑定的功能与类似

app.get('/', controller); 

当快递电话controller,它已经取得了100%的控制你。如果从controller同步引发异常,Express很不错,并且会将其视为您的错误。但是,只要调用任何异步代码,就有责任决定如何处理任何错误。

在高速的情况下,你有两个选择:

  1. 由于您是通过reqres,您可以捕获错误并发送你想返回给用户作出的任何反应。
  2. controller在Express中实际上具有function(req, res, next)的功能签名。这是一种非常常见的格式。

next回调预期被称为如果您在响应具有写任何东西。如果您不带任何参数调用next(),则这告诉Express看起来继续处理它具有的一组URL处理程序,试图找到一个将处理该请求的处理程序,如果找不到任何处理程序,则返回404。

但是,如果您将参数传递到next(如next(err)),Express将跳过其余的URL处理程序,而不是寻找错误处理程序。 Express允许您注册自定义处理程序,但如果没有找到,它将返回500.

那么你应该怎么做你的例子?你可能想是这样

function controller (req, res, next) { 
    find().then(function (result)) { 
     if (!result) throw new SpecificError("Couldn't find it."); 

     res.send("It exists!"); 
    }).catch(next); 
} 

这意味着,如果任何异常的承诺链内抛出,next功能将它称为,以及Express将在那里接手。

+0

是的,我认为这是对我如何使用'req','res'和'next'的误解。 – nmagerko

1

无极处理程序是“扔安全”。这意味着你在任何承诺处理程序中抛出的任何异常都会被自动捕获并转化为被拒绝的承诺。这是规范如何对承诺以及它们如何工作的书面(除了jQuery的承诺的某些版本,但是这只是因为他们没有按照规范)。

所以,如果你从你的承诺库中得到“未处理的拒绝”,那就是一个有用的警告,告诉你你有一个被拒绝的承诺,它没有处理它,所以拒绝被默默地忽略,通常是一个编码错误。

而且,事实上在你controller()功能,你必须正是:

function controller (req, res) { 

    // ... omitted ... 

    find().then(function (result)) { 
     if (result) { 
      // let 'res' be the Express response object 
      res.send("It exists!"); 
     } else { 
      // let SpecificError be a prototypical subclass of Error 
      throw new SpecificError("Couldn't find it."); 
     } 
    }).catch(function (error) { 
     // throw the error again, so that the error handler can finish 
     // the job 
     throw error; 
    }); 
} 

如果你站上罚球线的地方说throw new SpecificError,那么将会把承诺变成拒绝承诺。这会导致你的.catch()处理程序被调用。在那个处理程序中,你再次抛出这个将承诺作为被拒绝的承诺。因此,以find().then(...)开头的最初承诺现在将被拒绝承诺。但是,有没有更多的拒绝处理,并不必返回从controller()的承诺。所以,当时你有一个未处理的拒绝承诺。这通常是编码错误。

您有如何纠正这种编码错误的几种选择:

  1. 你可以通过调用某种错误处理功能,你传递错误给自己处理的错误在.catch()处理和传递res的说法,然后不要抛出错误。

  2. 您可以从controller()函数返回承诺,并且无论调用哪个代码,该函数都可以处理拒绝的承诺。

+0

为了解释为什么我得到这个错误,你肯定会得到满意的结果。由于其他答案提供了特定于Express的解决方案,因此我将不得不将其标记为解决方案。 – nmagerko