6 ms·
Great article; a few things I would add. I use bluebird for Promises, which is just the most fantastic Promises lib ever conceived, no joke; if you haven't used
by STRML 11y ago
Great article; a few things I would add. I use bluebird for Promises, which is just the most fantastic Promises lib ever conceived, no joke; if you haven't used it try it. So some of these may be Bluebird-specific:
1. Don't wrap callback functions manually with `new Promise(function(resolve, reject) {...})`, just use `Promise.promisify(...)`. For one-off functions, try `Promise.fromNode(function(cb) { fs.readFile('..', cb); });`.
2. This pattern:
getUserByName('nolan').then(function (user) {
return getUserAccountById(user.id);
}).then(function (userAccount) {
// I got a user account!
});
Could be:
getUserByName('nolan')
.get('id')
.then(getUserAccountById)
.then(function (userAccount) {
// I got a user account!
});
3. I too used Promise.resolve().then(...) to start a lot of route handlers. Try `Promise.try(function() {...})`, which is equivalent but reduces the temptation to just stick a synchronous value in the `Promise.resolve()` just because you can.
4. `Promise#nodeify()` is super useful for creating functions that return promises or use callbacks depending on how they're called. For example:
function getUserName(id, cb) {
return db.getUserAsync(id).get('name')
.nodeify(cb);
}
Is the same as:
function getUserName(id, cb) {
var promise = db.getUserAsync(id).get('name');
if (!cb) return promise;
promise.then(function(result) { cb(null, result);})
.catch(function(e) { cb(e); });
}
This is great if you want to convert a few functions you use to promises, but they're called elsewhere and expect a callback style.
I'm sure there are many more. This is my bible: https://github.com/petkaantonov/bluebird/blob/master/API.md https://github.com/petkaantonov/bluebird/blob/master/API.md
In short; use Promises! They are the answer for callback hell in Node. Async/await may fix more problems in the future but if you want Node/Browser compatibility and to get started right now, Promises are the best way to go.
- nolanl 11y agoBluebird is awesome. :) I especially love promisifyAll() and promisify(). The only reason I didn't include something like that in the post is that I didn't want to overwhelm newbies. I think it's already confusing enough what the difference is between q/when/RSVP/bluebird/jQuery promises/Angular promises, etc... And honestly, more and more I just use vanilla promises, or a tiny polyfill like Lie.
- ddoolin 11y agoAfter native promises, is there much reason to use 3rd party libraries? Promises are a pretty small set of tools, so I'm not sure what one would have to offer over another.
- STRML 11y agoFeatures, I suppose. Bluebird has many more helpers than the spec, and it may actually be faster than the first round of native Promises. We'll see how it evolves.
- realusername 11y agoThe stacktrace is much much better in Bluebird compared to native and there are lots of methods which are not available in the native one.
- inglor 11y agoBluebird is much faster and easier to debug than native promises. It is very feature rich and it runs _everywhere_. It also converts callback APIs to promises at one go. That said, on a client-side app there are cases where I'd use native promises. On the server - not a chance.
- esailija 11y ago(disclaimer: I am the author of bluebird) Thank you. I must say the most prominent feature of bluebird has always been "debuggability" (not perf). Long stack traces, unhandled rejection reporting and warnings for many of the mistakes you cover (coming in 3.0, some of them listed at http://imgur.com/a/t3xng http://imgur.com/a/t3xng) are just priceless, especially when working with people who are not promise ninjas.
- nolanl 11y agoThose new warnings are FANTASTIC. That's exactly what I meant when I said it's better for your tools to warn you, rather than trying to read and understand some lengthy article. :) BTW for PouchDB, we use bluebird in Node and lie in the browser, and bluebird has been truly indispensable for debugging. Looking forward to it getting even better!
- loganfsmyth 11y agoOverall, totally agree, just wanted to mention two things. 2) I've always found passing callbacks by name to be very difficult to read/follow, but this is a case where I think ES6 arrow functions will help readability a lot. getUserByName('nolan') .then(user => getUserAccountById(user.id)) .then(userAccount => // I got a user account!) 4) Your example isn't quite equivalent, you should be using the 2-param version of .then(), not .then().catch(). In your current code, if your cb threw an exception, it would call it a second time with the error from the first time.
- vkjv 11y agoAlso, fun is that `.nodeify(cb)` protects against undefined. So, it's a handy way to make your library support both promises and callbacks. module.exports = function (arg, optionalCb) { return promiseReturningFn(arg).nodeify(optionalCb); };