javascriptcallbackpromiseqbluebird

Aren't promises just callbacks?


I've been developing JavaScript for a few years and I don't understand the fuss about promises at all.

It seems like all I do is change:

api(function(result){
    api2(function(result2){
        api3(function(result3){
             // do work
        });
    });
});

Which I could use a library like async for anyway, with something like:

api().then(function(result){
     api2().then(function(result2){
          api3().then(function(result3){
               // do work
          });
     });
});

Which is more code and less readable. I didn't gain anything here, it's not suddenly magically 'flat' either. Not to mention having to convert things to promises.

So, what's the big fuss about promises here?


Solution

  • Promises are not callbacks. A promise represents the future result of an asynchronous operation. Of course, writing them the way you do, you get little benefit. But if you write them the way they are meant to be used, you can write asynchronous code in a way that resembles synchronous code and is much more easy to follow:

    api().then(function(result){
        return api2();
    }).then(function(result2){
        return api3();
    }).then(function(result3){
         // do work
    });
    

    Certainly, not much less code, but much more readable.

    But this is not the end. Let's discover the true benefits: What if you wanted to check for any error in any of the steps? It would be hell to do it with callbacks, but with promises, is a piece of cake:

    api().then(function(result){
        return api2();
    }).then(function(result2){
        return api3();
    }).then(function(result3){
         // do work
    }).catch(function(error) {
         //handle any error that may occur before this point
    });
    

    Pretty much the same as a try { ... } catch block.

    Even better:

    api().then(function(result){
        return api2();
    }).then(function(result2){
        return api3();
    }).then(function(result3){
         // do work
    }).catch(function(error) {
         //handle any error that may occur before this point
    }).then(function() {
         //do something whether there was an error or not
         //like hiding an spinner if you were performing an AJAX request.
    });
    

    And even better: What if those 3 calls to api, api2, api3 could run simultaneously (e.g. if they were AJAX calls) but you needed to wait for the three? Without promises, you should have to create some sort of counter. With promises, using the ES6 notation, is another piece of cake and pretty neat:

    Promise.all([api(), api2(), api3()]).then(function(result) {
        //do work. result is an array contains the values of the three fulfilled promises.
    }).catch(function(error) {
        //handle the error. At least one of the promises rejected.
    });
    

    Hope you see Promises in a new light now.