繁体   English   中英

NodeJS中的异步等待(尝试/捕获)

[英]async await (try/catch) in NodeJS

我正在研究 NodeJS API,我想知道ROUTES 文件中的以下 2 个示例中哪一个是最佳实践。 正如您在一个中看到的那样,我正在添加 try/catch,而在另一个中我没有。 请注意,在Service.js文件中,我也添加了 try/catch。 我是只在一个地方需要它还是在两个地方都使用它更好?

路线文件

 const todo = router => {
      /* EXAMPLPE 1 */
      router.get('/tasks', isAuth, async (req, res, next) => {
        const results = await TodoService.getTasks();
        return res.status(201).json(results);
      });

      /* EXAMPLPE 2 */
      router.get('/tasks', isAuth, async (req, res, next) => {
        try {
           const results = await TodoService.getTasks();
           return res.status(201).json(results);
         } catch (e) {
             return next(e);
         }
      };

服务.JS

class TodoService {
  static async getTasks() {
    try {
      const tasks = await TaskModel.find();
      return {
        message: 'Fetched posts successfully.',
        tasks: tasks,
        status: 200
      };
    } catch (err) {
      if (!err.statusCode) {
        err.statusCode = 500;
      }
      return err;
    }
  }
}

在您的问题的现在编辑版本中, getTasks()永远不能拒绝其 promise (因为您发现任何可能的拒绝并将它们变成已解决的承诺)。 因此,示例 2 中的调用者包含一个完全没有意义的try/catch ,它基本上是永远无法使用的死代码。 虽然看起来它可能是更安全的代码,但它基本上是浪费的代码。

在 function 的文档/合同中明确说明它是否可以拒绝。 如果不能,那么调用者就没有理由尝试处理拒绝,因为那只是毫无意义的代码。

就个人而言,我认为让错误通过被拒绝的 promise 回流可能更灵活,因为它可以在更多地方使用并且更容易与其他操作结合使用。 但是,如果唯一的目的是作为请求处理程序的一个部分,那么它可能会保存代码以集中拒绝捕获并将其转换为解析的 object,然后像现在一样返回。 对于不同类型的调用者不太灵活,但如果调用 function 的目的总是很窄,则可能更简单的代码来集中拒绝捕获。

没有正确/错误的答案。 这主要取决于您最想优化的内容(灵活的调用者使用与集中式错误捕获)和您的个人风格偏好。

不幸的是,在我写下这个答案之后,OP 编辑了他们的问题以使其有所不同。 此答案已写入问题的原始版本。

两者都可以正常工作,这真的是一个见仁见智的问题。

首先,您确保方法调用永远不会返回被拒绝的 promise,因此您不必在调用者中捕获拒绝。

在第二种情况下,您可以返回一个被拒绝的 promise,因此您必须在调用者中捕获拒绝。

就个人而言,每当我看到一个没有任何代码的await时,它看起来就像一个编码错误,所以你必须很好地记录该方法从不拒绝。 我个人认为如果错误拒绝并且调用者可以决定做什么,它会更灵活。 这允许该方法被更广泛的调用者使用,但确实需要调用者捕获拒绝。

另一方面,如果 function 的所有可能用途都在请求处理程序中,您所要做的就是返回没有拒绝的状态,以便可以将状态作为响应发送回,那么您可能通过捕获来节省代码错误集中在 function 中,而不是在每个调用者中。

就像我说的,这主要是编码风格偏好的问题。 您只需确保在某处处理任何可能的 promise 拒绝,以便始终对传入请求发送适当的响应。

这里的概念是有效的,但这是伪代码,我没有运行它。 另外,“引号”中的任何术语都不是正确的术语

使用 try catch 开发层次结构时要记住的重要一点是错误总是抛出三个。 因此,您应该始终确保您有一个最高级别的 try catch 以处理错误。

在您可能在服务中引发错误并在路由中处理它的情况下,您的服务最好保留为“纯功能”以赶上更高的水平。 我发现这会下意识地让你避免循环依赖 如果您想抛出自定义错误,您可能会在两个“级别”上使用 try/catch。

一个例子是:

// Router
Router.get('/tasks', async (req, res) => {
    try { 
        return await TodoService.getTasksById(taskId);
    } catch (err) {
        return errorResponseUtility(err.status, err.message);
    }
}

// Service
const getTasksById = async id => {
    try {
        return await DB()
            .connect('tasks')
            .select('*')
            .where({ id });
    } catch (err) {
        if(err instanceOf NotFoundError) throw err;
    }
}

// Error Defs
const NotFoundError = {
    status: 404,
    message: 'Resource could not be found'
}

这样,如果您没有任何错误,但以正确的方式与随机 502

其他:解构你的 req.params:

const { id: taskId } = req.params; // This renames id to taskId

或者,不要解构它,直接解析它,因为它只使用一次。

所以答案取决于代码风格。 Javascript 有很多结构代码的方法。 您的第一个选项更接近使用箭头 function 的功能样式,第二个选项是使用 ES2015 中引入的 class 设置。

但是,只有第一个实际创建了路由器。 因此,您仍然需要将 TodoService 中的 map 您的 static 方法编码到 URL。

来自 Java 的开发人员会发现基于 class 的代码更易于遵循。 有在快递中提供小型服务经验的人可能会发现第一个示例更容易理解。

作为开发人员,我个人的偏好是尽可能简单地在日志中调用 map API 调用代码。 我喜欢 express 的一件事是使用嵌套路由器和中间件是多么容易。

所以对我来说,你的第一个很接近。 我只是没有任何匿名函数。 相反,这些函数应该在一个外部文件中,可能是routes.js ,并且设置好以便您可以轻松地对它们进行单元测试。

例如

路由.js

function makeTaskRoute = function(TodoService) {
 return async getTasks(req, res, next) => {
    const results = await TodoService.getTasks();
    return res.status(201).json(results);
 }
}

module.exports = {
  makeTaskRoute
}

然后在 index.js

const TodoService = require('todo/service/TodoService.js');
const getTasks = require('./routes/routes.js').makeTaskRoute(TodoService);
const router = express.Router()

router.get('/tasks', getTasks);

这是一种更实用的风格,但也允许依赖注入和简单的测试。

要使这个更清洁,还有更多工作要做,而且很多都是偏好。 但我发现这一点(加上在 typescript 中使用声明的类型并干净地分离出数据结构和突变)是干净的、易于阅读的、易于维护和改进的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM