
Why are callbacks more “tightly coupled” than promises? - rdfi
http://stackoverflow.com/questions/21141817/why-are-callbacks-more-tightly-coupled-than-promises
======
jasallen
This is not a very good or complete answer as others are pointing out.

Promises allow you to make your async call in a context where you _don 't
know_ what has to be done next. You pass the promise around and attach to it
as needed (and chained if necessary), _that_ is the lack of coupling that is
so desirable.

~~~
RyanZAG
You can technically achieve this from callbacks as well. Simply pass in the
callback as a function to the method. This way you can still make your async
call in a context where you don't know what has to be done next - what will be
done next can be passed in dynamically to the function.

That said, I still much prefer promises as they make it much more explicit.

~~~
sanderjd
I'm confused by your comment.

> Simply pass in the callback as a function to the method. This way you can
> still make your async call in a context where you don't know what has to be
> done next - what will be done next can be passed in dynamically to the
> function.

That sounds like you're just describing how callbacks work in general... The
point is that you have to know what function to pass in at the time you make
the asynchronous call. With promises, you can figure that out later.

~~~
MBlume
Let's say I'm in the middle of the method foo, and I do some asynchronous
operation.

With a promise, I can do two things, I can pass it into some other function,
or I can return it to the caller of foo

with a callback, I can do two things, I can supply a callback which passes the
result into some function, or I can require that the caller of foo provide a
callback, which I pass along to the asynchronous operation I'm calling

these seem roughly isomorphic to me -- I guess a difference is that if I pass
the promise to a method I'm allowing the method to decide when to deref it,
but that seems different from the "tightly coupled" claim.

~~~
skybrian
It's a matter of timing. A callback function could be called immediately and
you need to be ready for that, so you need to define the callback _before_
passing it in. With a promise, you can call the then() method _after_ the
function returns; if the value is ready earlier then it will automatically be
cached until you pick it up. The looser requirements on timing result in
better decoupling; like any other value, you can put the promise in an
arbitrary data structure and pick it up any time later, or perhaps not at all.

If you want to do this with callbacks you'll need to implement a way to cache
the value and the result will be equivalent to a promise.

------
ollysb
As I mentioned in the comments, those examples aren't actually equivalent, the
callback version could be:

    
    
        var getData = function(callback){
            showLoadingScreen();
            $.ajax("http://someurl.com", {
                complete: function(data){
                    hideLoadingScreen();
                    callback(data);
                }
            });		
        };
    
        var loadData = function(){
            getData(doSomethingWithTheData);
        }
    
        var doSomethingWithTheData = function(data){
            //do something with data
        };

~~~
tyleregeto
Exactly. This is the problem I have with the hype around the promises API, and
if you're a Dart developer, Futures.

They claim to solve "callback hell" but they can't. Callback hell is the
result of poor programming style, not a limitation of the language. Callback
hell is just as possible with promises, and there are plenty of examples of it
on the internet.

I'm not saying promises don't have benefits, and can't result in some nice
programming patterns, but generally they are just a different way of doing the
same thing. It's not that callbacks are more tightly couples then promises,
its that people write their code that way.

Their API's have some other nice benefits though.

~~~
rubiquity
I think Callbacks, Promises and Futures are all more or less the same in terms
of coupling. However, I do find Futures to produce the most readable code.

------
batterseapower
Thinking about this from a Haskell perspective, it seems that with promises
the lambda waiting for the callback is basically encapsulated into the
promise:

    
    
      type Promise a = (a -> IO ()) -> IO ()
      getData :: Promise String
    

Whereas with callbacks you pass that around explicitly:

    
    
      getData :: (String -> IO ()) -> IO ()
    

Promises are a monad, so you get the usual monad advantages of being able to
"hide the plumbing" behind the abstraction, hence no tower of explicit
callbacks in your JS code.

    
    
      instance Monad Promise where 
        return x = \k -> k x
        fmap f p = \k -> p (k . f)
        mx >>= fxmy = \k -> mx (\x -> fxmy x k)

~~~
steveklabnik
> Promises are a monad,

Actually, they're not. Get ready: [https://github.com/promises-aplus/promises-
spec/issues/94](https://github.com/promises-aplus/promises-spec/issues/94)

~~~
jdonaldson
Promise A+ is scary bad. They're trying to shoehorn all of the functionality
of a monad based implementation into a single method: [http://promises-
aplus.github.io/promises-spec/#the__method](http://promises-
aplus.github.io/promises-spec/#the__method)

Of course, this relies on a lot of dynamic inspection and runtime checks. Of
course, this means that you can't compose with A+ promise methods in a
reliable way. Of course, this means that their implementation is not going to
be compatible with anyone else's. Of course, this means that everyone else's
version of promises is "broken".

If you're interested in approaches that follow algebraic/monad patterns, check
out fantasyland spec: [https://github.com/fantasyland/fantasy-
land](https://github.com/fantasyland/fantasy-land)

The name of the spec is a joke, but the spec itself is not. It's referencing a
very real sentiment: That developers that want to use formal composition
techniques in their js are living in a "fantasy land".

------
lightblade
I like harpo's answer better than the accepted answer. I'll help generate more
upvote for that answer from here :)

> The coupling is looser with promises because the operation doesn't have to
> "know" how it continues, it only has to know when it is ready.

> When you use callbacks, the asynchronous operation actually has a reference
> to its continuation, which is not its business.

> With promises, you can easily create an expression over an asynchronous
> operation before you even decide how it's going to resolve.

> So promises help separate the concerns of chaining events versus doing the
> actual work.

------
lhorie
Here's a contrived example:

Promises:

    
    
      //model
      User.get = function() {
        return getData();
      };
      User.getOdd = function() {
        return User.get().then(filterOdd);
      };
      
      //controller
      someControllerAction = function() {
        User.getOdd().then(redirectToHomepageIfEmpty);
      };
    

Callbacks:

    
    
      //model
      User.get = function(callback) {
        getData(callback)
      }
      User.getOdd = function(callback) {
        User.get(function(data) {
          if (typeof callback == "function") {
            callback(filterOdd(data));
          }
        });
      };
    
      //controller
      someControllerAction = function() {
        User.getOdd(redirectToHomepageIfEmpty)
      };
    

Notice how there's a little bit of noise required in the callback version of
User.getOdd - i.e. if (typeof callback == "function"). Ideally this kind of
noise is something that should be hidden at a framework level, and not show up
in application code.

Noise can get quite significant when the code is predominantly dealing with
asynchrony, e.g. try implementing this in callback style:

    
    
      jQuery.when(User.getOdd(), Pinterest.search("something")).then(doSomething)
    

It's doable, but it's messy, because the code that is supposed to be focused
on pinterest items and odd users now also needs to deal with flags indicating
which http request is done at which point.

------
taeric
I'm not sure this makes a strong case. Especially since in this case the
callback could be "simplified" by having it such that the callback example
looks like:

    
    
        void loadData = function(){
          showLoadingScreen();
          $.ajax("http://someurl.com", {
            complete: hideLoadingScreen(function(data){
              //do something with the data
            })
          });
        };
    

Where hideLoadingScreen is simply:

    
    
        function hideLoadingScreen(f) {
            return function(e) {
                f(e);
                doHide();
            };
        }
    

You could probably take this further. Though, I'm not sure how valuable that
is.

~~~
brlewis
In your code, loadData() function knows that the data is being fetched
asynchronously. In the posted code, loadData() doesn't have to know whether
getData() works synchronously or asynchronously.

~~~
taeric
Meh. With higher order functions, this could be achieved as well. I was
focusing on the "hide the loading screen" portion of the example.

And, honestly, it is not obvious to me when the loading screen gets hidden. In
the callback one, that is much more obvious. (Granted, this is as much from
familiarity.)

~~~
brlewis
Hiding synchronous vs. asynchronous with higher-order functions means doing it
with callbacks. It's generally hard to take a function that was originally
written to run synchronously and change it to run asynchronously without
changing the way it's called.

I don't see this as world-changing either, but I understand why people like
it.

------
fleitz
It's about reification...

Callbacks are an implementation of asynchronous processing each slightly
different sort of like 'function calls / calling convention' in assembler,
while promises provide a reified interface that is easier to think about
conceptually because you're thinking about what to do, not how to do it.

The contrived example in SO can just as easily be decoupled while still using
callbacks, however the promise based code 'looks' better because it more
concisely describes what's going on in terms of 'english'.

------
y1426i
Here's an example which might explain the decoupling a bit:

    
    
        // You may call this syntactic sugar
        var p1 = new Promise(function(response, reject) {
            setTimeout(function(){ 
                response(Math.random() * 1000); 
            });
        }).then(function(val){ console.log(val); return val; });
        
        // But here's the magical decoupled call
        p1.then(function(val) { console.log(val); });

------
pacaro
I can't work out if this is an “Async Tarpit” or an instance of the “Blub
Paradox”

Callbacks vs. Promises vs. Futures - they can all express the same things -
personally I like promises, but YMMV

