In node I/O bound operations — such as networking, databases, or file systems — are non-blocking or asynchronous (for good reason). This kind of programming naturally lends itself to callback driven APIs which in turn can lead to unwieldy nested callback structures. Which has affectionally been referred to as the “Pyramid of Doom” in this “article”:http://calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web/.
Promise-based APIs provide an alternative to callback-based APIs. More importantly, they solve the problem that callback APIs introduce: the readability and intent of asynchronous code.
h2. What are promises?
The idea behind Promise-based APIs is that a function will return a _promise_ for an object in the future. Promises can be chained together and as each promise is fulfilled the next promise in line is executed. If a promise can’t be fulfilled it raises an error which can be handled, otherwise the chain of promises stops execution.
So instead of:
We’d do something like this:
h2. The library
We went with a library named “Q”:http://github.com/kriskowal/q/ which provides the kind of functionality I demonstrated above. It is a fairly flexible library that has built in support for node style callbacks (function with error and result). However, we noticed the the third party node libraries may have a different set of callback conventions which required us to wrap them.
h3. Node-style example
Q provides a function named
ncall which takes a function, an object to execute that function on, and arguments. Q assumes that the first argument of the callback is an _error_ and the second argument is the _result_. If the error is non-null it assumes an error occurred and raises a failure. Otherwise it fulfills the promise with the given result.
h3. Wrapping non-compliant APIs
In the contrived example below we wrap a library that doesn’t use node-style callbacks. We use
Q.defer() to return a promise for a result in the future and wrap the
We also wrote this helper to automatically “qify” objects where it wraps methods on an existing object into “Q” style methods.
h2. Alternative to promises
“node-fibers”:https://github.com/laverdet/node-fibers is a library that provides a ‘blocking style’ way of executing asynchronous code. It doesn’t actually block (that would be bad), instead it uses continuations to defer the execution of code until an asynchronous operation has completed.