-
-
Notifications
You must be signed in to change notification settings - Fork 104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for throwing in async handlers. #69
Conversation
Async functions are just wrappers around functions returning promises. There’s an existing PR support promises. Have you looked at that? |
I may be wrong I think the solution in #47 would still log If this is the case I think (only my opinion) it should be avoided as it will fill up a lot of consumer's logs unnecessarily. It may not be as usable across versions as promises are, but the nice thing about |
You should give it a go and report back. It would work because it’s within the same tick. Technically there’s no way to “call a promise with a |
Also, the same comments apply here - you can throw a falsy value and return a falsy promise. You also need to be aware how confusing this will be for consumers - by giving examples of async functions, people will definitely be using transpilers such as Babel or TypeScript. They will not tell you it’s an async function however, since they only transpile down to returning a promise, so this feature can produce different results depending on development practices. |
This is not always true. I am actually working on my first production level api with node 10 and async/await right now. I am using the v4 router, so no async middleware, but I am running non-transpiled async functions. So the only real answer is to check Also, I will for sure start a beta version of my projects with |
Sorry, I didn’t mean to imply people will only be using transpilers, just that people many people transpile their code today using these tools, but depending on the emit output it will either work or not work for this PR. |
@blakeembrey in the case of transpiled code you will always get i.e. if (fn.constructor.name === 'AsyncFunction') {
return fn(req, res, next).catch(next)
}
try {
var result = fn(req, res, next)
if (result && typeof result.then === 'function') {
result.then(null, function (error) {
next(error || new Error('Promise rejected with: ' + error))
})
} catch(error) {
next(error)
} |
I know, that’s why I left the comment. You’ll notice the first response and PR is from myself. And you’ve validated the problem with using the constructor name, something that works on my machine might not work on your machine. For example, if I write a module using the router and publish it to NPM and I happen to be using the latest node, I’m now likely to get a bunch of issues with people not running the latest node who I then just have to point to here and say it’s a feature, not a bug. It’s not difficult to support promises first class instead, which was my comment. I’m also still not sure something is missing in my explanation. You do not need the first line to check the constructor. It’s returning a promise anyway. The only reason I imagine doing that is by routing these functions down a different code path for performance reasons (async functions won’t throw synchronous errors), but that shouldn’t be done where you wrote it - it should be done once otherwise you have a small impact by checking this same code path every time. |
@blakeembrey Apologies, I'm not sure I'm addressing all of your points in the below. I'll read over and have a think. What I'm getting at is that I agree your PR supports promises across the board, which I think having looked at it needs to be done regardless of this PR. What this PR has the added benefit of is that it will not raise any const prom = doSomethingAsync()
prom.catch(err => console.log(err)) but the following does not: const prom = doSomethingAsync().catch(err => console.log(err)) All my PR, having reflected on yours adds is protection against these warnings. It is safe on old versions of node (tried on 0.10.x) because |
@maxcbc Did you go and test it as I suggested in #69 (comment)? I have not replicated what you've said, and I don't believe I ever would be able to, because, as far as I understand, it works as I described in that same comment. I've attached this code and output as the example I've just run to demonstrate, please let me know if you see some fault in it. async function test () {
throw new Error('boom')
}
const result = test()
console.log(test.constructor)
if (result && typeof result.then === 'function') {
result.then(null, err => console.log(err)).then(() => console.log('done'))
} |
In fact, you can't even wrap it in |
I changed the branch base for this PR to |
Closing due to no follow up. |
Has any work on this been done in another place? A lot of closed issues refer to this PR, but now I see the PR has been closed due to no follow up. Is Express 5 going to support async route middleware with throwing errors, or do we still need to wrap each middleware in a wrapper? |
Brilliant, thanks! |
Add support for throwing in async handlers without
UnhandledPromiseRejectionWarning
What
AsyncFunction
, it will passnext
to the handler's.catch
.Why
This gives developers the freedom to throw again but also means they don't have to do the following pattern.
They can instead do: