Javascript NodeJS中的异步等待(try/catch)

Javascript NodeJS中的异步等待(try/catch),javascript,node.js,async-await,Javascript,Node.js,Async Await,我正在开发一个NodeJSAPI,我想知道ROUTES文件中的以下两个示例中哪一个是最佳实践。正如你所看到的,在一个例子中,我添加了try/catch,而在另一个例子中,我没有添加try/catch。注意,在Service.js文件中,我还添加了try/catch。我只需要在一个地方使用它,还是在两个地方都使用它更好 路由文件 SERVICE.JS 不幸的是,在我写下这个答案后,OP编辑了他们的问题,使之有所不同。这个答案是根据问题的原始版本写的 这两种方法都很好,至于你喜欢哪一种,真的是个意见

我正在开发一个NodeJSAPI,我想知道ROUTES文件中的以下两个示例中哪一个是最佳实践。正如你所看到的,在一个例子中,我添加了try/catch,而在另一个例子中,我没有添加try/catch。注意,在Service.js文件中,我还添加了try/catch。我只需要在一个地方使用它,还是在两个地方都使用它更好

路由文件

SERVICE.JS

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


这两种方法都很好,至于你喜欢哪一种,真的是个意见问题

在第一种方法中,确保方法调用永远不会返回被拒绝的承诺,因此不必在调用方中捕获拒绝

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

就个人而言,每当我看到一个wait时,它看起来就像一个编码错误,因为它没有捕获到拒绝的代码,所以您必须很好地记录该方法从未拒绝过的代码。我个人认为,如果错误被拒绝,那么调用方可以决定怎么做,这样会更灵活。这允许更广泛的调用方使用该方法,但需要调用方捕获拒绝

另一方面,如果函数的所有可能用途都在请求处理程序中,您只需要返回一个没有拒绝的状态,这样状态就可以作为响应发送回来,那么您可能是通过在函数中集中捕获错误而不是在每个调用方中捕获错误来保存代码

正如我所说,这主要是编码风格偏好的问题。您只需确保任何可能的拒绝承诺都在某个地方得到了处理,以便始终对传入的请求发送适当的响应。

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

在使用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

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

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

在单据/合同中明确该功能是否可以拒绝。如果不能,那么调用方就没有理由尝试处理拒绝,因为这只是毫无意义的代码

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


没有正确/错误的答案。这主要是一个问题,您最想优化的是灵活的调用方使用,而不是集中的错误捕获和您的个人风格偏好。

因此答案取决于代码风格。Javascript有很多方法来构造代码。第一个选项更接近使用箭头函数的功能样式,第二个选项使用ES2015中引入的类设置

然而,只有第一个真正创建了路由器。因此,您仍然需要代码将TodoService中的静态方法映射到URL

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

作为开发人员,我个人的偏好是尽可能容易地将日志中的API调用映射到代码。我喜欢express的一个特点是,使用嵌套路由器和中间件是多么容易

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

e、 g

routes.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中使用声明的类型,并将数据结构和突变清晰地分离出来,这样做的好处是干净、易于阅读、易于维护和改进。

两者都可以很好地发挥作用,人们喜欢哪一种,这实际上是一个意见问题。在第一种方法中,确保方法调用永远不会返回被拒绝的承诺,因此不必在调用方中捕获拒绝。在第二种情况下,您可以返回一个被拒绝的承诺,因此您必须在调用者中捕获拒绝。就个人而言,每当我看到一个wait时,它看起来就像一个编码错误,因为它没有捕获到拒绝的代码,所以您必须很好地记录该方法从未拒绝过的代码。我个人认为,如果错误被拒绝,那么调用方可以决定怎么做,这样会更灵活。@jfriend00啊啊,太好了!你可以随意把它作为一个答案来回答,以获取要点。现在,你编辑了你的问题,去掉了你调用的不同方法。请不要这样做,因为它改变了我写答案的问题。请把它放回我第一次回应时的样子。在这个新示例中,按照您编辑它的方式,第二个示例中的try/catch没有意义,因为它永远不会被命中。它看起来更安全,但实际上是死代码,这有点毫无意义。我总是选择第二个版本。您可能希望在一条路由上调用多个服务,那么捕获一次就容易多了。我想您的意思是向上-但通常人们会说向上,因为它没有分支
function makeTaskRoute = function(TodoService) {
 return async getTasks(req, res, next) => {
    const results = await TodoService.getTasks();
    return res.status(201).json(results);
 }
}

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

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