Hacker News new | ask | show | jobs
by davewasmer 4884 days ago
So, as far as I can tell, there are two benefits this article outlines: avoiding highly nested code, and handling certain types of errors better. Are there other benefits?

In my experience, promises can be more difficult to debug (once the promise library takes my callback, I can't follow the flow of execution until it is called, unless I crack open the library itself), and are less intuitive. While those shouldn't disqualify the idea immediately, it does make me hesitate.

And I'm not sold on the benefits to error handling either. In the author's example, yes, all those error handlers could be grouped together - but how often do you have that many async function calls with identical error handlers? In most situations, that is a warning sign that you aren't handling errors properly and with enough "resolution".

All that said, I don't think promises are useless. There may be times when it makes sense to use them. But calling them the "next great paradigm in JavaScript programming" seems like a bit of a stretch to me.

2 comments

The article immediately dives into what promises actually are, and you've done excellently at summarizing possible benefits from the examples listed.

I would advise most strongly against this exercise in extrapolation: it is not a productive tasks to introduce a new technology via use cases without establishing some grounds for what the technology's role is. You've attempted to define, after reading, what that role is, and that to me bespeaks a horrible exercise that will draw bad results, and it speaks to a poor likely fruitless introduction for people who don't already know.

The net is this: a promise is a value you have, can pass around, can chain more promisary stages of computation on to, or combine with other promises that describes something of the future. You have a symbol for the future that you can continue to operate on. That is the value of promises: it's just an object. There are no other JS constructs we have for a first-class future: the promise is the sum of taking as much away from asynchronous as we can, for boiling the asynchronous future down into a mundane, primitive value. It's surpassing notability is that a promise is just an object, unlike everything else we have for reasoning about the future.

In callback style, one has to know ahead of time what one is doing in the future and have a function fully specified to deal with that. I see promises are fairly close to event style programming using only .once handlers, but the libraries for promises also focus on tasks like combining promises (Q.all, Q.allResolved) and there is chainability and error handling inbuilt: these sum to making Promises far easier to use in practice than I have events.

At least in node, you usually pass errors all the way back up the call chain. With normal callback style error handling, you have to put "if (err) return cb(err)" after each async call. It's crazy.

With promises, you can attach an error handler once. If you think of errors as only unexpected conditions, you can have a single error handler for each set of operations and not have to worry about checking at each step.

> With normal callback style error handling, you have to put "if (err) return cb(err)" after each async call. It's crazy.

Or use a sane async library. As far as I can tell, something like https://github.com/caolan/async gives you a strict superset of Promise features, unless you're for some reason tied to how code with promises looks.

You can wrap your callback functions and handle errors all in one spot. Example:

    var slice = Array.prototype.slice;

    function errHandler(callback) {
      return function(err) {
        if(err) {
      // Error handling code here.
        } else {
          callback(slice.call(arguments, 1));
        }
      };
    }
I've tried stuff like this before, but it clutters your code pretty bad anyway, doesn't it? You have to do something like this:

    function myAsyncThing(cb) {
        var handleErrors = errHandler(cb)
        doSomethingElse(handleErrors(function(data) {
            // repeat. use handleErrors at each callback. 
        }))
    }
    
Am I missing something? Can you get it cleaner than that?
That depends, if you're using doSomethingElse a lot I'd just go ahead and wrap that as well, if you're using it once it's no big deal.

  doSomethingElse(errHandler(function(real, results) {
    // foo
  }));
  
If you're using Node you should be writing small(ish) modules anyways, so it doesn't lead to much code blote and its advantageous to consolidate your error handling in one or 2 spots.