简体   繁体   English

快速错误处理和异步等待

[英]Express error handling and async await

In my Node.js app I added the following code to catch every uncaught exception: 在我的Node.js应用程序中,我添加了以下代码来捕获每个未捕获的异常:

process.on('uncaughtException', function (err: Error) {
    try {
        logger.err(err);
    } catch (err) {

    }
});

The problem is that Express has its own default error handler, which catches every uncaught exception. 问题是Express有自己的默认错误处理程序,它捕获每个未捕获的异常。 Now, Express caught the exceptions before Node (process.on), so my logger didn't get reached. 现在,Express在Node(process.on)之前捕获了异常,因此我的记录器没有到达。 However, it's possible to add another error handler that can catch every exception before Express does: 但是,可以在Express之前添加另一个可以捕获每个异常的错误处理程序:

app.use(logErrors);

function logErrors (err: Error, req: Request, res: Response, next: NextFunction) {
    logger.err(err);
    next(err);
}

This still doesn't cover every case. 这仍然不包括每一个案例。 Whenever I have an async function that I call with await , there's no exception, but a rejected Promise is returned instead. 每当我有一个我用await调用的async function ,没有异常,但是返回了被拒绝的Promise。 For example: 例如:

app.get('/foo', async function (req: Request, res: Response, next: NextFunction) {
    await bar();
});

function bar() {
    throw new Exception();
}

won't reach my logErrors function because it won't throw, but will return a rejected Promise. 将无法访问我的logErrors函数,因为它不会抛出,但会返回被拒绝的Promise。

So to fix it, I wrapped my Express HTTP handlers with another function: 所以为了修复它,我用另一个函数包装了我的Express HTTP处理程序:

app.get('/foo', wrap(async function (req: Request, res: Response, next: NextFunction) {
    await bar();
}));

function wrap(func: (req: Request, res: Response, next: NextFunction) => void) {
    return async function (req: Request, res: Response, next: NextFunction) {
        try {
            await func(req, res, next);
        }
        catch (err) {
            next(err);
        }
    }
}

next(err) passes the error to my handler. next(错误)将错误传递给我的处理程序。 Now, I manage to catch the exceptions to my logErrors function. 现在,我设法捕获我的logErrors函数的异常。

I'm almost done. 我就快完成了。 I still have one case in which I can't catch the errors. 我还有一个案例,我无法发现错误。 It happens when I call an async function without the await keyword (It's sometimes useful to use the same function in two different places in the code, once calling in asynchronously, and once synchronously). 当我在没有await关键字的情况下调用async function时会发生这种情况(有时在代码中的两个不同位置使用相同的函数,一次异步调用,并且一次同步调用)。 So this code won't catch the error: 所以这段代码不会捕获错误:

app.get('/foo', wrap(async function (req: Request, res: Response, next: NextFunction) {
    bar();
}));

What's happening here is that the Express HTTP handler returns a resolved Promise to the wrap function. 这里发生的是Express HTTP处理程序将已解析的Promise返回给wrap函数。 The wrap function in turn, does not reach the catch block, so it does not call to next(err) which would reach my logger. 依次包装函数没有到达catch块,所以它不会调用next(err)来到我的记录器。

bar function in turn, returns a rejected Promise, but there is no one waiting for its return value. bar函数反过来,返回一个被拒绝的Promise,但是没有人等待它的返回值。

How can I change my code in such a way I won't end up with any unhandled Promise rejection? 如何以这样的方式更改我的代码我不会以任何未处理的Promise拒绝结束? (only generic solution) (只有通用解决方案)

There is another process.on event you can set up a listener for - unhandledRejection . 还有另一个process.on事件,你可以为 - unhandledRejection设置一个监听器。

You can use it to handle those rejections all over the code. 您可以使用它来处理整个代码中的拒绝。

NOTE : remember to terminate your process after you logged everything you needed. 注意 :记住在记录所需内容后终止进程。 More on this here . 更多关于这里

I've found a solution: 我找到了一个解决方案:

app.get('/foo', async function (req: Request, res: Response, next: NextFunction) {
    dontAwait(() => bar());
});

async function dontAwait(func: () => void) {
   try {
       await func();
   }
   catch (err) {
     logErrors(err);
   }
}

I still have one case in which I can't catch the errors. 我还有一个案例,我无法发现错误。

You could, but you currently simply don't do anything with the result. 你可以,但你目前根本没有对结果做任何事情。 If you want your usual error handlers to trigger, you need to await it. 如果您希望触发通常的错误处理程序,则需要 await它。

It happens when I call an async function without the await keyword 当我在没有await关键字的情况下调用async function时会发生这种情况

I can't see any good reason for that. 我看不出有什么好的理由。 But if you really want to fire and forget the function , you can do it. 但是如果你真的想解雇并忘记这个功能 ,你就可以做到。 You just have to handle errors explicitly: 您只需要明确处理错误:

bar().catch(e => logger.err(e));

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

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