-
Notifications
You must be signed in to change notification settings - Fork 12
Alternative error handling #4
Comments
I'm not sure the multiple-return from function asyncOp() {
var rej
setTimeout(() => {
rej(new Error('ok'))
})
return new Promise((resolve, reject) => {
rej = reject
})
}
try {
var res = await asyncOp()
} catch(err) {
console.log(err) // "ok"
} cc'ing @domenic who knows more about this than I do :) |
Yes, I think @vkurchatkin is suggesting abandoning exceptions and error bubbling in favor of multi-value return (like Go, IIUC). So the promise returned would always fulfill, and would fulfill with a [err, res] tuple. I don't like it, as I think exceptions and error bubbling add a lot to programming in general. But I know there are many who disagree with me there. |
@domenic right, inspired by Go mostly. It's basically exceptions vs errors. Exceptions are invalid input, etc. If one wants an error to bubble they can explicitly rethrow it. |
I agree. They can be kind of a mess in C++, but in garbage-collected languages they're pretty nice. Manually handling every error at the callsite makes it hard to group errors naturally, easy to forget to handle them, and arduous to get the errors back to code that can usefully handle them. In short, it's exactly what we have now with node style callbacks, and a big part of what Promises would make better :) |
The main issue with try/catch exception handling is that it only allows you to deal with a problem once it had turned catastrophic. The stack is gone, all the execution context is blown out, and the best you can do is work with the serialization to figure out what happened. Literally anything you can do is better than that, in that anything else you could do would allow you to work with a problem in the course of failing rather than after it has failed catastrophically. |
I don't see why any of that is true... In the cases we're discussing here, they're isomorphic. |
@domenic FYI, I edited your reply because the email support in GitHub flipped out for some reason. Please doublecheck to make sure it is correct. |
Yeah all good, thanks. #windowsphoneproblems |
I agree it should be exceptions, never return values, for reasons outlined in http://yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs-typical-code.html. However the language constructs when using async/await are insufficient, it will need a typed and/or predicated catch statement and a
There is no difference between error codes and exceptions WRT to this, you can try catch any call just like you can check the error code of any call. But since you are only going to propagate the error to the caller anyway, automatic propagation of exceptions is very nice and you don't need the try catch. |
In my personal experience this is incredibly true. Even if it’s now out of the spec, _CancellationError_s are very difficult to manage in ES2015 |
cancellation can be managed via runners like |
.return is not implemented anywhere |
@petkaantonov I use regenerator which has it and firefox has it. Just because current v8 is not spec compliant does not mean we should ignore it. |
Copying from nodejs/node#5020
For what it's worth, almost every other dynamic language has it (e.g. Python) and people use it all the time. In addition, it could be a predicate - but I just wanted to give an example of how I'd deal with it. People have been using promises with
Promise rejections do not only symbolize programmer errors. This is fundamental and goes to the mental model of promises - it's what they do conceptually. Promises were born to serve as proxies for values - rejections symbolize regular exceptions and regular exceptions are not always programmer errors in the JavaScript language. Even things that are not programmer errors you'd want to bubble - it is about ownership and control - very often you can't deal with the vast majority of errors - it is about responsibility and passing it on the same way |
I wonder how examples from OP would evolve: let [err, res] = await asyncOperation();
if (!err && res != null) {
// do stuff
} How is this better than callbacks or throwing? |
Copying from nodejs/node#5020 A good way to reason about exceptions and organize EH code is to follow the contract metaphor:
If There are a few places in an application where contracts get looser. In these functions you can catch exceptions and still satisfy the contract. A typical example is a top level HTTP request dispatcher. At this level the contract becomes very loose and very generic; something like: "dispatch the request and return an HTTP response, either a success one (2xx, 3xx) or an error one (4xx, 5xx)". This is the right place to You also need to be careful about releasing resources and restoring program invariants but that's where These classical EH patterns had become unusable in callback code because exception bubbling goes to the event loop instead of the logical caller. |
@YuriSolovyov let [err, res] = await asyncOperation();
if (err) throw err; // reject my own promise - what else can I do??
// do stuff Instead, you should just write: let res = await asyncOperation();
// do stuff. There is also the fact that error codes get in the way. They force you to decompose any expression that contains async calls. With error codes, you cannot write something as simple as: let res = syncOp(await asyncOp()); Exceptions allow you to clearly separate the EH code. Your logic is not broken / polluted by error checks, and you can review the exception handling logic separately. |
@petkaantonov FYI, I wrote a babel plugin to just patch |
With ES2015 destructuring we could get something like this:
We can return result as object, array or both.
The text was updated successfully, but these errors were encountered: