This is not a very good or complete answer as others are pointing out.<p>Promises allow you to make your async call in a context where you <i>don't know</i> what has to be done next. You pass the promise around and attach to it as needed (and chained if necessary), <i>that</i> is the lack of coupling that is so desirable.
As I mentioned in the comments, those examples aren't actually equivalent, the callback version could be:<p><pre><code> 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
};</code></pre>
Thinking about this from a Haskell perspective, it seems that with promises the lambda waiting for the callback is basically encapsulated into the promise:<p><pre><code> type Promise a = (a -> IO ()) -> IO ()
getData :: Promise String
</code></pre>
Whereas with callbacks you pass that around explicitly:<p><pre><code> getData :: (String -> IO ()) -> IO ()
</code></pre>
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.<p><pre><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)</code></pre>
I like harpo's answer better than the accepted answer. I'll help generate more upvote for that answer from here :)<p>> 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.<p>> When you use callbacks, the asynchronous operation actually has a reference to its continuation, which is not its business.<p>> With promises, you can easily create an expression over an asynchronous operation before you even decide how it's going to resolve.<p>> So promises help separate the concerns of chaining events versus doing the actual work.
Here's a contrived example:<p>Promises:<p><pre><code> //model
User.get = function() {
return getData();
};
User.getOdd = function() {
return User.get().then(filterOdd);
};
//controller
someControllerAction = function() {
User.getOdd().then(redirectToHomepageIfEmpty);
};
</code></pre>
Callbacks:<p><pre><code> //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)
};
</code></pre>
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.<p>Noise can get quite significant when the code is predominantly dealing with asynchrony, e.g. try implementing this in callback style:<p><pre><code> jQuery.when(User.getOdd(), Pinterest.search("something")).then(doSomething)
</code></pre>
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.
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:<p><pre><code> void loadData = function(){
showLoadingScreen();
$.ajax("http://someurl.com", {
complete: hideLoadingScreen(function(data){
//do something with the data
})
});
};
</code></pre>
Where hideLoadingScreen is simply:<p><pre><code> function hideLoadingScreen(f) {
return function(e) {
f(e);
doHide();
};
}
</code></pre>
You could probably take this further. Though, I'm not sure how valuable that is.
It's about reification...<p>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.<p>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'.
Here's an example which might explain the decoupling a bit:<p><pre><code> // 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); });</code></pre>
I can't work out if this is an “Async Tarpit” or an instance of the “Blub Paradox”<p>Callbacks vs. Promises vs. Futures - they can all express the same things - personally I like promises, but YMMV