Callbacks or Promises? Why not both…

Some people like Promises, some people like Callbacks. I’m more in the Callbacks camp if I’m honest, but I can see the appeal of both sides. Recently, I wondered how hard it would be to make my functions support both Promises and Callbacks, depending on the preference of the user. Turns out, it’s not so hard…

Callback vs. Promise

Here’s my quick example — a function that checks whether a number is less than ten or not, and responds accordingly.

Here is the callback example:

simple callback example

And here is the Promise example:

simple promise example

Both functions manage both the success and failure cases, and this should be nothing new to most JavaScript developers.

So how do we merge the two? What does that look like? It’s actually fairly simple…

Here’s the code, including examples of how to call this function with and without callbacks (hint: simply don’t pass in a callback!):

The basis of this implementation is to setup the function using Promises as we did above, but here we need to make sure to capture the resulting Promise in a variable (i’ve called it ‘promise’).

After setting up your Promise we want to do a check to see if a callback has been provided. If we didn’t provide a callback, then we simply return the promise — easy! If we did provide a callback though, we need to do something else to call it.

It’s pretty easy to do, and you can see what’s happening between lines 9 and 14. The only complication is the use of JavaScripts ‘bind’ method, and the assumption we are using the common convention of using callbacks with an error and data arguments — in that order.

The first argument of the ‘then’ method is the Promises ‘resolve’ function — i.e. the function we call if everything works the way we expect it to. On line 11 of the example above, we are binding our callback function — giving it a context of null (so it uses the default), and also passing null in as the first argument to the callback, which is our error argument.

This returns a new function that is expecting one final argument — the data argument. This is provided when we call resolve.

On the next line, we are simply passing our callback function as the second argument to the ‘then’ method. This is the reject method of the Promise.

Whatever we pass into reject will get passed as the first argument of our callback function — which is our error argument! Nothing gets passed to the data argument, but that’s ok because we don’t want to do that!

And that’s that…