直接执行代码可正确引发异常,但在函数内则不会

时间:2019-07-07 15:24:41

标签: promise async-await graphql

我正在尝试在异步代码中引发异常。如果我直接这样扔,那就可以了。示例:

  Query: {
    requisitions: async (parent, args, { req }, info) => {
      const user = await Auth.findOne({ _id: req.session.userId }).select('roles')
      if (!user.roles.some(role => ['driver', 'requestant'].includes(role))) {
        throw new ForbiddenError(ErrorCodes.UNAUTHENTICATED)
      }

      return true
    }
}

但是,如果我创建了一个辅助函数来处理此问题,它将无法正常工作。我需要帮助程序功能,因为在应用程序的很多地方都需要进行角色检查。

  Query: {
    requisitions: async (parent, args, { req }, info) => {
      hasRights(req, ['driver', 'requestant'])

      return true
    }
}

export const hasRights = async (req, allowedRoles) => {
    const user = await Auth.findOne({ _id: req.session.userId }).select('roles')
    if (!user.roles.some(role => allowedRoles.includes(role))) {
      throw new ForbiddenError(ErrorCodes.UNAUTHENTICATED)
    }
}

注意:hasRights是从另一个文件导出的。

我已经尝试了两个文件中try / catch块的所有组合,但是我只是在服务器控制台中获得了UnhandlePromiseRejectionWarning,但是requisitons解析器继续执行。如果要抛出异常,我希望它停止。我不知道为什么它只能以一种方式起作用而不能以另一种方式起作用,即使它是同一件事。任何帮助表示赞赏。谢谢。

1 个答案:

答案 0 :(得分:1)

调用hasRights(req, ['driver', 'requestant'])可以返回被拒绝的承诺,但是您没有代码可以处理该承诺。因此,这是未处理的拒绝。

当内联引发时,它会被async requsitions()函数捕获,然后该函数返回被拒绝的承诺,因此requisitions()的调用者有机会捕获它。

您可以通过在hasRights()调用之前添加await来确保以相同的方式处理从hasRights()返回的被拒绝的诺言:

Query: {
  requisitions: async (parent, args, { req }, info) => {
    await hasRights(req, ['driver', 'requestant'])
    return true
  }
}

这将使async requisitions()函数能够像原始内联hasRights()一样自动捕获来自throw的拒绝。

当然,您必须确保在requisitions()的调用方中正确处理被拒绝的诺言。


在我看来,您还需要知道在throw函数中执行async会被async函数自动捕获,并转化为对以下承诺的拒绝:由async函数返回。这是async函数的功能。