Not romantically binding [promise-ring wraps Node.js callbacks with native ES6 Promises]
JavaScript Promises are a powerful way of working with asynchronous code. They make sequencing operations easy and offer a clear, predictable way to handle errors that might occur along the way. Much has been written about the benefits of Promises and I won't try to repeat it here.
What I do hope to do is make Promises a slightly more natural part of the Node.js development experience.
In version 0.12.* (as well as in io.js), ES6 Promises are natively available.
But the standard set of modules (such as File System) still use their original callback-based design and there's a bit of a disconnect between how you might want to write something and how you're able to.
Fortunately, most of the Promise libraries that are already available include wrappers to convert callback-based functions into ones that return a Promise
.
However, most of those libraries assume you'll be using their custom implementation of Promise
(from the "olden days" when that was the only option).
And while different Promises/A+ implementations are meant to be interoperable, it seems silly to pull in a second Promise
implementation when a perfectly good one is already available.
That's where promise-ring
comes in: it's a tiny npm package that provides functions to convert typical callback-based APIs into their Promise
-based counterparts using the V8 JavaScript engine's native Promise
implementation.
Briefly:
promise-ring
is small, simple library with no dependencies that eases the use of native JavaScript Promises in projects without a Promise library.
Documentation is available in the README along with runnable samples demonstrating the use of each API.
It's all quite simple and exactly what you'd expect.
A bonus feature is the wrapAll
function which makes it easier to work with modules that expose many different callback-based functions (such as the File System module; see below).
For an example of using promise-ring
and Promises to simplify code, here is a typical callback-based snippet to copy a file onto itself:
var fs = require("fs");
// Copy a file onto itself using callbacks
fs.stat(file, function(err) {
if (err) {
console.error(err);
} else {
fs.readFile(file, encoding, function(errr, content) {
if (errr) {
console.error(errr);
} else {
fs.writeFile(file, content, encoding, function(errrr) {
if (errrr) {
console.error(errrr);
} else {
console.log("Copied " + file);
}
});
}
});
}
});
And here's the same code converted to use Promises via promise-ring
:
var pr = require("promise-ring");
var fsp = pr.wrapAll(require("fs"));
// Copy a file onto itself using Promises
fsp.stat(file)
.then(function() {
return fsp.readFile(file, encoding);
})
.then(function(content) {
return fsp.writeFile(file, content, encoding);
})
.then(function() {
console.log("Copied " + file);
})
.catch(console.error);
The second implementation is more concise, easier to follow, and DRY-er. That's the power of Promises! :)
Find out more by visiting promise-ring on GitHub or promise-ring in the npm gallery.