Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Stop Trying to Catch Me (jlongster.com)
102 points by jlongster on April 7, 2015 | hide | past | favorite | 19 comments


>Not only is this a ton of boilerplate

Bluebird has an overload of catch() that takes in a parameter for the error class. https://github.com/petkaantonov/bluebird/blob/master/API.md#...

>I don't care about losing the stack (which is inherent in any async work).

Bluebird gives stack traces across async frames.

>but it breaks an important feature of JavaScript debuggers: break on exception. If you have break on exception enabled, and you make an error inside getValue, it now pauses on the throw in the above code instead of inside getValue where you actually made the mistake.

This is true, although for errors thrown explicitly with throw your debugger will stop at the actual throw site.

The good thing is the original exception's stack is maintained, so you know when it came from and can set a bp next time.

>It's cool, I just don't understand why everyone is so excited about a simple syntactic improvement.

The excitement is related to the comparative ES5 code (state machine) that would be needed to achieve it, not the ES6 code (generators). Everyone knows that async/await is a simple wrapper around generators - LukeH's original proposal describes it as such.

Edit: (And of course await is much clearer than a yield and remembering to wrap the outermost async function in spawn())


Also, you can just use Bluebird's .error() for catching "operational errors": https://github.com/petkaantonov/bluebird/blob/master/API.md#...

Where an operational error "represents an error (that) is an explicit promise rejection as opposed to a thrown error."


Just wanting to add to this - bluebird indeed solves many of the problems in the post (even the 'unimportant' ones like having to call .done). It is absolutely worth looking into.

I should also point out that while bluebird doesn't crash the process on uncaught exceptions, it does print a stack to stdout - and you can fairly easily have a catch-all handler in whatever framework you are using to display/process uncaught exceptions in the desired format. This is what express-promise-router does, for example.


If it's any consolation, I also dislike promises, though I don't know that much about them. I feel they don't solve the problem they set out to solve, "callback hell" or cleanly interleaving async and sync code together, and I don't find their syntax aesthetic. I feel JSONP, message passing and state machines are cleaner. I'm unsure why many love promises, and was surprised by the level of what I'm only comfortable describing as "standards fever" over the emergent promises spec.

I also think arrows are cool.

Ah, that was refreshing. Thanks you for having the courage to buck the promises trend, which contributed to inspiring me to speak my mind as well! :)

BTW -- your karma is enormous. What's with that?


I agree. I feel that we're kind of forced to use them at this stage, with new browser APIs etc, but they don't actually seem to make code any less verbose or more maintainable.


OP is James Long, a really well known + awesome and insightful writer and thinker on topics mainly around JS.


Perhaps this clarifies the possibilities of promises a bit? https://coderwall.com/p/ehzcuq/concurrency-in-js-is-easy-wit...


It's a good overview. I'm thinking about it now :)

Examples 3 and 4 are very neat. And they do make sense as a way to have a pipeline operate on a range of values which may or may not have resolved yet. They promise consistency regardless of the "readyState" of the resource. And the syntax could even be shortened with property getters to something like:

pipe.read(x).split.map(upper).join.write(y)

Which is okay.

There's still something I dislike about them. I really just like the pattern where everything is a separate service, which send messages to each other. You can have message queues, and all services can operate simultaneously, and distribute them across wherever, you can hot-swap them, they're totally de-coupled, parameter formats aren't limited to Node-style callbacks. And each service can be "programmed" with a state machine, so everything is totally declarative, and totally expressive. Throw in complex event processing and you can do anything. I just really like SoA, and think if you're going to bother trying to create a solution for the "async opportunity" you may as well do the most awesome one possible.

I think I mostly get what promises do and how they're useful -- I don't get why I'd use them over just JSONP and callbacks for something where I'm not trying to create such an epic solution.

Fundamentally tho I think one major reason contributing to my choice to not use promises is maybe I'm comfortable with the ambiguity of a value that a value hasn't resolved yet, I don't need to pretend there's something there when it isn't!! :)

Or maybe I just have "trust issues", and I don't trust promises in general, no matter what language you say 'em in! :)

Yeah, that's probably a reason contributing, too -- I like SoA because everything takes care of its own stuff. No need to promise, just do!!


The first time I used Promises (and really, the first time I did any serious work in Node), I prototyped an isomorphic web server:

https://github.com/appsforartists/ambidex/blob/master/src/Am...

In three different places in that file, you'll find a Promise that ends in ".catch(error => console.error(error.stack))`. Before I learned that bit of boilerplate, I'd spend an hour staring at my screen wondering why things were silently broken.

It's mindblowing that errors are implicitly suppressed by default with Promises. console.error ought to be automatically invoked for any error that makes it to the root scope without a .catch() (just like it is with sync code).


In Python it's possible, with the use of destructors (like in Twisted). I don't think it's possible in Javascript.


> A newbie to JavaScript will write that code, and be totally bewildered when nothing happens.

The above statement is applicable to a huge number of situations in JS. I'm surprised that so little has been done about it.


Agreed. An exception being silently caught and ignored by es6-promise was the culprit of a bug hunt that took a lot longer than it could have if the exception had automatically percolated to the console. I know now about the infinite try-catch of Promise so it won't be as much of an issue, but I think it would be better if the exception were uncaught (or re-thrown) if there are no more handlers on the promise chain. (Not sure how the library would know that though)


Thats why bluebird eschews the ability to attach error handlers later in favor of logging errors from all rejected promises that don't have an error handler at the next turn of the event loop. The result is a much more pleasant development experience.


How is this not a bug in your code? It sounds like you are not handling all your thrown exceptions? Just the "expected" ones?

Why would you do that?


Yes, it was a bug. We did have code in place at the top level to catch unforeseen exceptions, but it didn't occur to us that we needed to do so inside the promise as well. We fixed the issue, but finding it was a lot harder than it needed to be because there was no indication of why something didn't work, only that it didn't.


Yep. It is quite annoying. I remember working with some promise-library (bluebird iirc), which completely replaced error handling, including the stack traces. I was working with transpiled code, and the browser could always give me really helpful stack traces, for normal code, because of the .map files. That libraries stack traces were useless and made debugging frustrating and time consuming.


Bluebird should work just fine in conjunction with .map files. At least in node it definitely does - we've had no problems debugging typescript code and getting the actual lines in the typescript file via `source-map-support` [1]

[1]: http://npm.im/source-map-support


I ended up removing instances of try catch and also setTimeout 0 (or equivalent nextTick) in the promise library I use. Those two things caused me enough grief on several occasions to force my hand and modify the library's implementation. The setTimeout one especially baffled me... The straw that broke the camel's back for me was how it broke IndexedDB transactions


> It's cool, I just don't understand why everyone is so excited about a simple syntactic improvement.

async-function-star is a pretty interesting concept that it at least theoretically makes possible; AKA being able to both yield and await in a function.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: