admin管理员组文章数量:1316540
In my Node.js app I added the following code to catch every uncaught exception:
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. Now, Express caught the exceptions before Node (process.on), so my logger didn't get reached. However, it's possible to add another error handler that can catch every exception before Express does:
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. 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.
So to fix it, I wrapped my Express HTTP handlers with another function:
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. Now, I manage to catch the exceptions to my logErrors
function.
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). 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. The wrap function in turn, does not reach the catch
block, so it does not call to next(err)
which would reach my logger.
bar
function in turn, returns a rejected Promise, but there is no one waiting for its return value.
How can I change my code in such a way I won't end up with any unhandled Promise rejection? (only generic solution)
In my Node.js app I added the following code to catch every uncaught exception:
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. Now, Express caught the exceptions before Node (process.on), so my logger didn't get reached. However, it's possible to add another error handler that can catch every exception before Express does:
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. 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.
So to fix it, I wrapped my Express HTTP handlers with another function:
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. Now, I manage to catch the exceptions to my logErrors
function.
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). 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. The wrap function in turn, does not reach the catch
block, so it does not call to next(err)
which would reach my logger.
bar
function in turn, returns a rejected Promise, but there is no one waiting for its return value.
How can I change my code in such a way I won't end up with any unhandled Promise rejection? (only generic solution)
Share Improve this question edited Jan 10, 2017 at 14:38 Alon asked Jan 10, 2017 at 13:28 AlonAlon 12k28 gold badges103 silver badges172 bronze badges 10- 1 I think it would be a bad idea and actually impossible to call async function synchronously. You can ignore the fact that the function is async and call it, but it will still run asynchronously, you will just get the problems you describe. So my suggestion is not to use async functions in the sync manner - they are pletely different beasts. – Amid Commented Jan 10, 2017 at 13:42
- @Amid they are not really sync. What I meant is: when I call it without 'await' is asynchronous. When I call it with 'await' is synchronous (not really, but kind of: The code is executed line by line, but the thread is available to handle other requests every time I call a promise under the hood). – Alon Commented Jan 10, 2017 at 13:46
- That is what I mean. By calling async function without await you get this kind of problems. They are not actually supposed to be called this way, and your example with exceptions that are really not exceptions but promise rejections is a good illustration why. So I would not remend doing so even in case if they are the last line of some minor event handler or such - it would still be a good practice to call them with await. – Amid Commented Jan 10, 2017 at 13:49
- @Amid you're right, I agree with you and I always call async functions with 'await' even if it's the last line of a task. I did it that way because I wanted to return a response to the client without making him wait. How else can I do that? I've heard that it's not a very good idea to call to res.end() because it will skip middlewares that are supposed to be executed. – Alon Commented Jan 10, 2017 at 14:04
- I think you have to choose here. Either you return execution to client and it will not get any information about errors/exceptions. Or you wait for async operation to plete and have all info available. – Amid Commented Jan 10, 2017 at 14:07
3 Answers
Reset to default 2There is another process.on
event you can set up a listener for - 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.
It happens when I call an
async function
without theawait
keyword
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));
本文标签: javascriptExpress error handling and async awaitStack Overflow
版权声明:本文标题:javascript - Express error handling and async await - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742005356a2411843.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论