7 ms·
Bluebird – A full-featured, fast promises library for JavaScript
- spion 13y agoSome really impressive optimization techniques used in this library :) What's also really impressive is that ultra-fast means callback-level performance. And that performance is achieved even though promises are exception-safe (and don't crash the process like exceptions in callbacks ;) In fact, this library may become the turning point that causes node.js userland to start switching to promises...
- onestone 13y agoImpressive indeed. A post by the author in the main NodeJS group (https://groups.google.com/forum/#!forum/nodejs https://groups.google.com/forum/#!forum/nodejs) would be great.
- scotth 13y agoLike what?
- spion 13y agoLike function templating using the Function constructor, try-catch wrapping, closure avoidance and many more. The source is a goldmine of JS optimization techniques (some V8-specific, some not so much)
- gruseom 13y agoThis sounds very interesting even to those of us who don't need a promises library. If you or anyone else would like to go into detail, I bet a lot of people here would care (including me).
- scarmig 13y agoI'll second that. Might be appropriate for a series of blog posts, even.
- esailija 13y agoThanks for your interest - the optimization guide is planned to go over everything I have done.
- spion 13y agoesailija is the author, and I believe he mentioned that he is planning to write an optimization guide (specific to the library, though it will probably contain generally useful info).
- dmak 13y agoI would definitely love to read up more on how and why things are optimized the way the are.
- andreypopp 13y agoKew[1] is still faster, working on a pull request with updated benchmarks which include Kew. [1]: https://github.com/Obvious/kew https://github.com/Obvious/kew
- andreypopp 13y agoOk, sometimes kew is faster, sometimes bluebird, submitted a PR
- spion 13y agoHere are some results from my benchmark [1] results for 20000 parallel executions, 1 ms per I/O op file time(ms) memory(MB) promiseishBluebird.js 1076 76.08 async.js 2634 113.79 promiseishKew.js 2654 123.50 promiseishQ.js 56508 804.21 note: async.js is basically waterfall from https://github.com/caolan/async https://github.com/caolan/async [1]: https://github.com/spion/async-compare https://github.com/spion/async-compare
- davexunit 13y agoThis isn't related to the library, but promises in Javascript are much different than what I learned about promises in Scheme. In Javascript, promises seem to be about asynchronous operations. In Scheme (and other languages?), promises are used for lazy evaluation. Scheme provides the delay and force forms for this. Now I need to make sure that I don't get confused about this in the future.
- zeckalpha 13y ago> Now I need to make sure that I don't get confused about this in the future. Are you going to delay or force that?
- ufo 13y agoFor a functional programming analogy, JS promises are more like monads than about lazy evaluations. I don't know if there is a good Scheme analogy because in Scheme you can use call/cc and friends while in JS you are forced to write your async code in explicit continuation passing style (promises are just a way to make this a bit more manageable).
- j_m_b 13y agohttp://this-plt-life.tumblr.com/post/55420560033/when-somebody-offers-me-promises-as-a-replacement-for http://this-plt-life.tumblr.com/post/55420560033/when-somebo...
- 6cxs2hd6 13y agoAnother fan of that blog. I imagine you could re-caption the "Simon Peyton-Jones adding the IO Monad to Haskell" GIF [1] to serve this topic, too. [1]: http://this-plt-life.tumblr.com/post/44462204757/simon-peyton-jones-adding-the-io-monad-to-haskell http://this-plt-life.tumblr.com/post/44462204757/simon-peyto...
- deeteecee 13y agohahaha, nice
- antihero 13y agoI'm not sure if I'm doing things quite right, but I got a simply Postgres server script working. https://gist.github.com/radiosilence/6826930 https://gist.github.com/radiosilence/6826930 Could this be improved?
- esailija 13y agoIt looks like you are creating wrappers manually, that could be improved. Look into both overloads of [`Promise.promisify`](https://github.com/petkaantonov/bluebird/blob/master/API.md#promisepromisifyobject-target---object https://github.com/petkaantonov/bluebird/blob/master/API.md#...)
- antihero 13y agoI did try to Promisify the pg library but it didn't seem to work, and just broke :(
- esailija 13y agoHmm. Can you post your code and description of the problem as an issue? https://github.com/petkaantonov/bluebird/issues https://github.com/petkaantonov/bluebird/issues
- antihero 13y agoHere you go! https://github.com/petkaantonov/bluebird/issues/5 https://github.com/petkaantonov/bluebird/issues/5
- statico 13y agoIf it's useful, here's an app I converted to promises: https://github.com/artillery/pull-request-viewer/blob/master/prviewer.coffee#L392 https://github.com/artillery/pull-request-viewer/blob/master... It uses Q, not bluebird, but should still be relevant.
- acemarke 13y agoI'm finally starting to wrap my head around the concepts involved in promises, and was able to find a couple places to use them in my current rewrite of a JS codebase. However, my initial search doesn't show any articles describing why I should pick one of these over the other, particularly if they all implement the Promises/A+ spec. Would someone be kind enough to give me some idea what the meaningful differences are between Q, when, and bluebird?
- dclowd9901 13y agoWhat you want is a library that is fast (like the one mentioned), and is easy to debug. Most promises libraries don't implement a good stack trace. The one submitted for this article has what looks like a pretty amazing stack tracer, and is quite fast. If it truly follows the Promises A+ spec (which I'm sure it does), it's probably your best bet.
- domenicd 13y agoI will speak mostly to Q, since I am a co-maintainer. Q has historically stemmed from the work of Mark Miller, one of the authors of the E programming language, from which JavaScript promises are largely inspired. As such, it aligns with his larger goals for a promise ecosystem, which include object-capability security and using promises as proxies for remote objects. For an example of promises applied in these contexts, see his paper at [1]. In practice, all of this is somewhat theoretical, as Q also serves a large constituency of "normal" promise users in Node and the browser. There, it differentiates itself via a focus on features and integrity over speed (mainly as a matter of prioritization; we like speed too!); excellent Node.js integration [2]; and an internal system which allows promises for remote objects via Q-Connection [3] (but also gives some nice methods for promises for objects etc. for the same-machine case [4]). I would say that Q is my favorite library to work with, as it has thought out its design choices in a depth I don't see in the other libraries---or perhaps more accurately, the choices they have made don't align with my sense of craftsmanship as well :). That said, you should probably not use it if your concern is speed. We have always taken the position that, while speed is nice, most of the time you are doing an asynchronous operation anyway, so any overhead from the promise library will matter very little. [1]: http://research.google.com/pubs/pub40673.html http://research.google.com/pubs/pub40673.html [2]: https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks https://github.com/kriskowal/q/wiki/API-Reference#interfacin... [3]: https://github.com/kriskowal/q-connection https://github.com/kriskowal/q-connection [4]: https://github.com/kriskowal/q/wiki/API-Reference#promise-for-object-methods https://github.com/kriskowal/q/wiki/API-Reference#promise-fo...
- domenicd 13y agoAs a co-maintainer of Q, and author of the ES6 promise spec, this is extremely impressive work. I have had the privilege of watching it develop over the last few weeks, and am nothing short of amazed with what the author has done. The speed of this library opens up many doors for putting promises in places where previously some might have considered them not-low-level enough.
- dmak 13y agoI'm curious, could you explain why this is impressive and why it may or may not be better than Q?
- shuzchen 13y agoLooks awesome, I've been using JS Promises recently and it's made control flow a lot easier to handle. I've been using Vow, because I like having an .always() that gets called after the promise was handled (rejected or fulfilled), but sadly that library eats tracebacks (at least, I can't figure out a way to do it). Bluebird looks promising, but IE<9 isn't supported at the moment (https://github.com/petkaantonov/bluebird/issues/3 https://github.com/petkaantonov/bluebird/issues/3). Rules it out for most of my projects.
- oakaz 13y agoI code and enjoy JavaScript for years, and rarely feel like my heart feels feels squeezed when I look at a JavaScript library. Call me hater, but, I would never use it and anything depending on it.
- bronson 13y agoYou're a hater if you don't at least attempt to explain your feeling. Why even post that? Did you think you were participating in a poll?
- oakaz 13y agoYes, I can explain: the source code is horrible, readme is horrible. What it does: not clear. How it's different: not clear. Project name: bird?! Modularity: Poor. one single JavaScript file with hundreds of lines :( Duplicate effort, nothing new but more confuse. I'm just tired of seeing shitty Promises libraries. And I'm a huge hater for those. Here is a good one that I liked: https://github.com/puffnfresh/fantasy-promises https://github.com/puffnfresh/fantasy-promises
- spion 13y agoI'm sorry, but: 1. Its a promise library. It gives you a Promise class, a PromiseResolver and some tools to convert node functions to promises or to support dual promise/callback API. 2. Its super-fast and has full stack traces that go back until the beginning of the async event chain 3. I will skip this, because, uhh... 4. You didn't look hard enough. https://github.com/petkaantonov/bluebird/tree/master/src https://github.com/petkaantonov/bluebird/tree/master/src 5. Yes, promises are confusing. I'm going to write a straight-forward introduction (that uses bluebird) this weekend. But once you get past the new words and definitions, promises are actually not complicated at all. Infact, here is a short intro: How are promises different? Instead of writing your functions to take callbacks, you write functions that return promises. Imagine that node's fs.readFile returned a promise instead of taking a callback. Then this code: fs.readFile(file, function(err, res) { if (err) handleError(); doStuffWith(res); }); would look like this: fs.readFile(file).then(function(res) { doStuffWith(res); }, function(err) { handleError(); }); Pretty much the same so far, except you use a second callback for the error (which isn't really better). So when does it get better? Its better that you can attach a callback later if you want. Remember, `fs.readFile(file)` returns a promise now, so you can put that in a var: var filePromise = fs.readFile(file); // do more stuff... filePromise.then(function(res) { ... }); Okay, that's still not much of an improvement. How about this then? You can attach more than one callback to a promise if you like: filePromise.then(function(res) { uploadData(url, res); }); filePromise.then(function(res) { saveLocal(url, res); }); Still not good enough? What if I told you... that if you return something from inside the .then() callback, then you'll get a promise for that thing? Say you want to get a line from a file: var linePromise = fs.readFile(file).then(function(data) { return data.toString.split('\n')[line]; }); var beginsWithHelloPromise = linePromise.then(function(line) { return /^hello/.test(line); }); Thats pretty cool. But the coolest thing is probably this: if you return a promise from within `.then`, you will get that promise outside of `.then`: function readUploadAndSave(file, url, otherPath) { // read the file var filePromise = fs.readFile(file); // upload it when done reading var uploaded = filePromise.then(function(content) { return uploadData(url, content); }); // also save to another place locally var savedLocal = filePromise.then(function(res) { return fs.saveFile(res, otherPath) }); // return a promise that "succeeds" when both saving and uploading succeed: return Bluebird.join(uploaded, savedLocal); } readUploadAndSave(file, url, otherPath).then(function() { console.log("Success!"); }, function(err) { // This function will catch *ALL* errors, from the above // operations including any exceptions thrown inside .then console.log("Oops, it failed.", err); }); Now its easier to understand the chaining. At the end of every function passed to a `.then()`, return a promise. Lets make our code even shorter: function readUploadAndSave(file, url, otherPath) { // read the file return fs.readFile(file).then( // upload and save when done reading return Bluebird.join(uploadData(url, content), fs.saveFile(res, otherPath)); }); } What if we want to make sure the data is uploaded first before saving? function readUploadAndSave(file, url, otherPath) { // read the file var uploadedPromise = fs.readFile(file).then( // return promise that its uploaded return uploadData(url, content); }); return uploadedPromise.then(function() { // return promise that its saved. return fs.saveFile(res, otherPath); }); } Or even shorter, skip the temporary promise variables and chain .then the way we chain `stream.pipe` in node: function readUploadAndSave(file, url, otherPath) { // read the file return fs.readFile(file).then( // then upload it return uploadData(url, content); }).then(function() { // after its uploaded // save it return fs.saveFile(res, otherPath); }); } And similarly to how in a stream.pipe chain the last stream is returned, in promise pipes the last returned promise is returned. Thats all you need, really. The rest is just converting callback-taking functions to promise-returning functions and using the stuff above to do your control flow. Ah, and also, you can also return values in case of an error. So for example, to write readFileOrDefault (which returns a default value if for example the file doesn't exist) you would do this: function readFileOrDefault(file, line, defaultContent) { return fs.readFile(file).then(function(fileContent) { return fileContent; }, function(err) { return defaultContent; }); }
- deleted 13y ago[deleted]
- deleted 13y ago[deleted]
- cwmma 13y agoI'm not really seeing the speed on a fairly realistic perf [1] involving communicating with a web worker. Wrote a big blog post looking into this a couple weeks back [2]. [1]: http://jsperf.com/promise-comparisons/55 http://jsperf.com/promise-comparisons/55 [2]: http://calvinmetcalf.com/post/61761231881/javascript-schedulers http://calvinmetcalf.com/post/61761231881/javascript-schedul...
- esailija 13y agoWhen I say performance, I mean throughput not latency. That's why there are no latency benchmarks. Also, in your benchmark you do output in bluebird section with console.log. Maybe try http://jsperf.com/promise-comparisons/50 http://jsperf.com/promise-comparisons/50.
- cwmma 13y agothat one uses window.addEventListner which gives an advantage to libraries that prefer that to ones that use that one first over ones that use messageChannel first. here is a fixes one[1], looks like everything using mutation observer is about the same throughput. My background is that I've been trying to create a promise library that just creates without also being underscore for promises [1] What sort of performance are we talking about that we are able to test without really measuring other things. For instance when was able to dominate many of the perfs by actually doing many of them synchronously in cases where other libraries would force it async. [1]: http://jsperf.com/promise-comparisons/59 http://jsperf.com/promise-comparisons/59 [2]: https://github.com/calvinmetcalf/lie https://github.com/calvinmetcalf/lie
- esailija 13y agoThat's not throughput. You are running exactly 1 promise in parallel at a time and waiting for it to be resolved. However, on node.js you can have more than 1 client served by your server. For instance, your server could have e.g. 10000 promises/callbacks/generators active at a time. Take a look at how different solutions handle that https://github.com/spion/async-compare/blob/master/latest-results.md https://github.com/spion/async-compare/blob/master/latest-re.... The results don't change at all if we for example increase latency of I/O by an order of magnitude - that's why latency is not an interesting metric for this use case. It's pretty intuitive, all the 10000 users will just get their results 9ms later but the fact that we could even handle them in the first place without crashing our server matters. ---------- You are right that for your use-case, pretty much the only thing that matters is what implementation is used for queuing async calls since it's such a tight bottleneck. Bluebird attempts to use mutation observer if available.