Create a gist now

Instantly share code, notes, and snippets.

Promise You Call Me Back

Promise You Call Me Back

by Rafał Pocztarski

One of my answers on Stack Overflow where I explain the difference between promises and traditional callbacks on the example of AJAX in jQuery - jQuery: Return data after ajax call success - had a 4th birthday few days ago and it still gets upvotes so I decided to explain few concepts that I think are important but rarely considered.

I noticed that there are many people who prefer callbacks, or promises, or events - as though they were all equivalent ways to do the same thing in a different style - but they are not. Of course they are equivalent in some sense in a way that you can do with one what you can do with the other, but there is some impedance mismatch that is often overlooked.

Using events vs. promises is not like using using curly braces vs. indentation to divide code in blocks. It's more like using functional programming vs. object oriented programming. You can always translate one into another but some problems are naturally closer to one of them. They are like hammers and screwdrivers.

As I recently wrote in I/O API of My Dreams: The things that are perfect for events will not work well with promises. The things that are perfect for promises will not work well with events.

Now, what about callbacks? Callbacks are absolutely essential for both. Callbacks are what both events and promises are made of. And callbacks is what is made by both events and promises. In a way callbacks are at a lower level of abstraction and a higher lever of abstraction at the same time. Think about it.

To listen for events you register a certain kind of callbacks as event listeners.

To get the value of promises you use a different kind of callbacks.

I rarely see discussions of events vs. callbacks. But I often see arguments of promises vs. callbacks. Why is that? You make promises with callbacks and you use promises with callbacks. In a way there are only callbacks but with certain conventions.

Let's say that I have an API like this one, using Node style callbacks (just another convention, like promises) and you call it like this:

doSomething(function (error, result) {
    if (error) {
        // we have error
    } else {
        // we have result
    }
});

How it would look using promises?

doSomething().then(function (result) {
    // we have result
}).fail(function (error) {
    // we have error
});

Ok, it's different. But is it really that different?

What if you get a promise but you prefer the if (error) { ... } way of handling errors? You can use nodeify. What if you get a Node-style callback API but you prefer working with promises? You can use denodeify. So if you get not what you like it's easy to convert it. That's a relief. It doesn't really matter what you get. But if so then what's the point?

What promises get you that's hard with Node-style callbacks (and no, I won't talk about error handling, and I won't talk about complex cases of concurrency - that can be done with async perfectly well) is really separating the act of calling the asynchronous code with the act of registering callbacks.

If you use the promise API from the example above you don't have to give it a callback right away. You can store a promise in a variable:

var x = doSomething();

You can pass this variable to functions, return from functions, store it in objects or arrays, give it to five different places in your code - that at some later point in time will all be able to resister their own callbacks to get the data that is eventually produced by the original asynchronous function:

nodeify(some.promise[17].with.a.past, function (error, result) {
    if (error) {
        // we have error
    } else {
        // we have result
    }
});

Wait, this is a Node-style callback! Yes, that's the point. If you don't like the promise API then you can use the Node-style callbacks and still take advantage of the fact you don't have to register your callbacks at the same time and place where you call the asynchronous API.

And that is what is conceptually most important about promises. This and the fact that you don't have to like or even use the promises API if you don't like it will eventually lead to their universal adoption. I promise. Call me back in few years if I'm wrong.

Rafał Pocztarski GitHubrsp GitHubpocztarski

Short URL: https://bit.ly/callbackpromise
Twitter cut'n'paste:
Promise You Call Me Back by @pocztarski https://bit.ly/callbackpromise
Share it:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment