4 ms·
var Promise = require('bluebird'); var fs = Promise.promisifyAll(require('fs')); Promise.spawn(function* () { var data = yield fs.readFileAsync(somefi
by spion 13y ago
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
Promise.spawn(function* () {
var data = yield fs.readFileAsync(somefile);
});
Documentation: https://github.com/petkaantonov/bluebird/blob/master/API.md https://github.com/petkaantonov/bluebird/blob/master/API.md
My favorite example is doing a diff using an async diff service which provides a function `svc.diff(string1, string2)`. But also imagine that you need to preprocesses the files using the sync function `removeEmptyLines(buffer)`. This is how the function looks like when implemented using Bluebird:
function diffTwoFiles(f1, f2) {
var file1 = fs.readFileAsync(f1).then(removeEmptyLines),
file2 = fs.readFileAsync(f2).then(removeEmptyLines);
return Promise.join(file1, file2).spread(svc.diff);
}
I'd love to see someone come up with a better example using callbacks and async.
- nailer 13y ago- Why BlueBird? What's wrong with Q? - Isn't data a scope down? - https://github.com/petkaantonov/bluebird/blob/master/API.md https://github.com/petkaantonov/bluebird/blob/master/API.md is API based, not task based. async is API based too, but the API has names like 'waterfall' and 'parallel'. I can click them because I know what they mean. Promises just makes me feel like I'm reading about and endless series of abstractions.
- spion 13y agoThere is nothing wrong with Q, but Bluebird is a bit more node-oriented and also has really, really low CPU/memory overhead (lower than caolan's async). Also it provides the best debugging experience, period - because of its long stack traces spanning multiple previous async events. I didn't quite understand the comment about data being a scope down. What do you mean? Yes, promises do have quite a steep learning curve :/ However they're a lot more flexible than a utility grab-bag of functions that never quite fit the problem you're having. By that I mean I often had to massage my functions (by creating new closures or using bind etc) to make them fit the signature that async requires. I wrote a bunch of examples for common tasks here - http://promise-nuggets.github.io/ http://promise-nuggets.github.io/
- nailer 13y ago+1 examples. For me, nearly everything .waterfall(), .each(), or .parallel(), and has been for two years now.
- woah 13y agoThanks for the awesome blog post. I read it extensively when I was trying to use promises for everything. I ended up deciding that it was not worth the trouble of learning a lib with like 30 methods for a tiny bit of syntax sugar. Callbacks have never even really bothered me. Named functions FTW.
- spion 13y agoThose methods are there for convenience. Most of the time while I'm working with promises, I don't use anything else except `Promise.all` and `Promise.prototype.then`. Similarly how to when working with caolan's async, most of the time you don't use anything else except waterfall, series, parallel, mapSeries and map. (Note however that async's utility grab bag approach results with a larger commonly used subset :P) Promises are not about syntax sugar. They're about utilizing the whole power of the language and providing a parallel for most features found in synchronous code: 1. Functions have return values When using node style callbacks, we're ignoring the fact that the language was designed with functions that have return values. Instead we use half-functions. Its no wonder those compose quite badly - the language wasn't designed for that kind of composition. The language was designed to work with functions that take input values and return an output value. Callback-based functions do only the first half. Thats why to get them to compose we resort to a bunch of hairy helpers and boilerplate code. Callback-based functions that don't return anything are seriously crippled in power, and promises fix that, restoring much of the power. 2. Errors can bubble like exceptions When using node style callbacks, we must explicitly handle all errors. On one hand, this is a good thing: we should deal with all errors. On the other hand, its quite tedious: most of the time we can't deal with the error at the exact place it appears but must pass it up one level in the call chain. Promises do the error bubbling automatically. We can attach the appropriate error handler at the appropriate place to deal with the error. This simple feature results with tons of useful patterns, one of which is the ability to manage resources with constructs like C#'s `using` keyword. - https://github.com/spion/promise-using https://github.com/spion/promise-using 3. Values in variables can be accessed multiple times When using node style callback and event emitters, we must make sure to "capture" the value exactly when it comes. If we don't do that, poof, its gone forever - we missed it. In contrast, promises will keep the value for us. If we need to access that value later, we can simply attach another callback handler. An example where this may be useful is a database connection: We initialize the connection and get a promise for that connection: var pConn = db.connect(host, port); How do we implement a query method that is immediately available and will queue up queries until the connection is established? Easily: function query(q, params) { return pConn.then(function(conn) { return conn.queryAsync(q, params); }); } It doesn't matter whether the connection was established a long time ago or hasn't been established yet - the query will either execute immediately or its execution will be delayed until the connection becomes available. Now try doing this with callbacks :)
- lightblade 13y agoNative Promises already landed Chrome 32 and Q still does not support native promises. Bluebird delegate to native if supported. Promises can be used as flow control, but more importantly, it's an object that encapsulates asynchronous mechanics. I like to see how async can launch an asynchronous operation, then allow listeners to be attached later to capture the result. Now, you may say that if you want to attach listeners to capture result, you'll want to use event emitters. True, but event emitters has its own problem because event emitting and attach listeners are synchronous. What if the event was emitted before any body has a chance to attach listener to it? Promises does not have these issues.
- domenicd 13y agoThis is false. Bluebird does not and never will delegate to native promises.
- lightblade 13y agook... then can you explain what's happening here: https://github.com/petkaantonov/bluebird/blob/master/js/browser/bluebird.js#L27 https://github.com/petkaantonov/bluebird/blob/master/js/brow... Where the line checks for `window.Promise`
- jhrobert 13y agoUsing async, if you want something to allow listeners to be attached later: var outcome = Boxon(); fs.readFile( "test.txt", outcome ); // Attach listener later: outcome( function( err, content ){ ... } ); See https://github.com/JeanHuguesRobert/l8/wiki/AboutBoxons https://github.com/JeanHuguesRobert/l8/wiki/AboutBoxons Boxon objects are light compared to promises, but they interop well. Best of both worlds!
- benesch 13y agoFor more on why bluebird crushes Q, check out the original HN thread: https://news.ycombinator.com/item?id=6494622 https://news.ycombinator.com/item?id=6494622 In short, its API is nearly as extensive as Q's with essentially no overhead—bluebird is hardly more expensive than callbacks, while Q is something like 10x slower than using callbacks.