In a perfect world, every function that started an async task would return a Promise. Unfortunately, most JavaScript APIs (including the native functions available in all browsers and in Node.js) are callback-based, not Promise-based. In this section, we’ll see how Promises can be used with callback-based APIs.
The most straightforward way to use Promises with a callback-based API is to create a Deferred and pass its trigger function(s) as the callback argument(s). For example, with a simple async function like setTimeout, we’d pass our Deferred’s resolve method.
| var timing = new $.Deferred(); |
| setTimeout(timing.resolve, 500); |
In cases where an error could occur, we’d write a callback that conditionally routes to either resolve or reject. For example, here’s how we’d work with a Node-style callback:
| var fileReading = new $.Deferred(); |
| fs.readFile(filename, 'utf8', function(err) { |
| if (err) { |
| fileReading.reject(err); |
| } else { |
| fileReading.resolve(Array.prototype.slice.call(arguments, 1)); |
| }; |
| }); |
(Yes, you can use jQuery from Node. Just npm install jquery and use it like any other module. There’s also a self-contained implementation of jQuery-style Promises, simply called Standalone Deferred.[36])
Writing this out routinely would be a drag, so why not make a utility function to generate a Node-style callback from any given Deferred?
| deferredCallback = function(deferred) { |
| return function(err) { |
| if (err) { |
| deferred.reject(err); |
| } else { |
| deferred.resolve(Array.prototype.slice.call(arguments, 1)); |
| }; |
| }; |
| } |
With that, we can write the previous example as follows:
| var fileReading = new $.Deferred(); |
| fs.readFile(filename, 'utf8', deferredCallback(fileReading)); |
In Q.js, Deferreds come with a node method for this right out of the box.
| var fileReading = Q.defer(); |
| fs.readFile(filename, 'utf8', fileReading.node()); |
As Promises become more popular, more and more JavaScript libraries will follow jQuery’s lead and return Promises from their async functions. Until then, it takes only a few lines of code to turn any async function you want to use into a Promise generator.
18.116.69.53