

Bluebird – A full-featured, fast promises library for JavaScript - esailija
https://github.com/petkaantonov/bluebird

======
spion
Some 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...

~~~
scotth
Like what?

~~~
spion
Like 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
This 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
I'll second that. Might be appropriate for a series of blog posts, even.

~~~
esailija
Thanks for your interest - the optimization guide is planned to go over
everything I have done.

------
domenicd
As 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
I'm curious, could you explain why this is impressive and why it may or may
not be better than Q?

------
acemarke
I'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?

~~~
domenicd
I 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#interfacin...](https://github.com/kriskowal/q/wiki/API-
Reference#interfacing-with-nodejs-callbacks) [3]:
[https://github.com/kriskowal/q-connection](https://github.com/kriskowal/q-connection)
[4]: [https://github.com/kriskowal/q/wiki/API-Reference#promise-
fo...](https://github.com/kriskowal/q/wiki/API-Reference#promise-for-object-
methods)

~~~
rektide
"ref_send", the ability to create a deliverable value, would be my core
linkage on Q and more-so promises (as not an author)
[http://waterken.sourceforge.net/](http://waterken.sourceforge.net/) .

The background is interesting, but I'm not sure what value an association with
historical context brings. I've tried other promise libraries, but stub my toe
on missing capabilities I'm used to, or end up distracted with mechanics. I
don't think I've ever found myself saying, gee, would that this be closer to
ref_send, but then again almost all implementations happen to tack close to.
So, uh, Domenic does have a more useful account of Q. Mostly here to drop some
ref_send. ;)

------
j_m_b
[http://this-plt-life.tumblr.com/post/55420560033/when-somebo...](http://this-
plt-life.tumblr.com/post/55420560033/when-somebody-offers-me-promises-as-a-
replacement-for)

~~~
6cxs2hd6
Another 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-
peyto...](http://this-plt-life.tumblr.com/post/44462204757/simon-peyton-jones-
adding-the-io-monad-to-haskell)

------
andreypopp
Kew[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)

~~~
spion
Here 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)

------
cwmma
I'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-
schedul...](http://calvinmetcalf.com/post/61761231881/javascript-schedulers)

~~~
esailija
When 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
that 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
That'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-
re...](https://github.com/spion/async-compare/blob/master/latest-results.md).

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.

------
davexunit
This 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
> 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?

------
shuzchen
Looks 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.

------
antihero
I'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
It 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#...](https://github.com/petkaantonov/bluebird/blob/master/API.md#promisepromisifyobject-
target---object))

~~~
antihero
I did try to Promisify the pg library but it didn't seem to work, and just
broke :(

~~~
esailija
Hmm. 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
Here you go!
[https://github.com/petkaantonov/bluebird/issues/5](https://github.com/petkaantonov/bluebird/issues/5)

------
oakaz
I 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
You'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
Yes, 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
I'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;
        });
      }

~~~
pjs67123
I like your examples. As one who is casually familiar with promises, I would
find it helpful to see more promise patterns/recipes. In particular, how about
a blog post on the promise equivalents to the
[https://github.com/caolan/async](https://github.com/caolan/async) Collections
and Control Flow methods (since that library seems to be heavily used in the
node community)? Would a higher level promises utility library be appropriate
or overkill?

~~~
spion
Yes, I could include that in my guide. Since promises are actual values, most
of the tools in async.js become unnecessary and you can just use whatever
you're using for regular values, like your regular array.map / array.reduce
functions combined with some promise tools like .all

You already have async.waterfall and async.auto with .then and .spread
chaining.

    
    
      files.getLastTwoVersions(filename)
        .then(function(items) {
          // fetch versions in parallel
          var v1 = versions.get(items.last),
              v2 = versions.get(items.previous);
          return [v1, v2];
        })
        .spread(function(v1, v2) { 
          // both of these are now complete.
          return diffService.compare(v1.blob, v2.blob)
        })
        .then(function(diff) {
          // voila, diff is ready.
        });
    

async.map is straightforward.

    
    
      // download all items, then get their names
      var pNames = ids.map(function(id) { 
        return getItem(id).then(function(result) { 
          return result.name;
        });
      });
      // wait for things to complete:
      Promise.all(pNames).then(function(names) {
        // we now have all the names.
      });
    
    

If you want to wait for the previous item to download first (ala .mapSeries)
thats also pretty straightforward: you just need the previous download to
complete, then run the next download, then extract the item name, and thats
exactly what you express in the code:

    
    
      // start with current being an "empty" already-fulfilled promise
      var current = Promise.fulfilled();
      var namePromises = ids.map(function(id) { 
        // wait for the previous download to complete, then get the next
        // item, then extract its name.
        current = current
          .then(function() { return getItem(id); })
          .then(function(item) { return item.name; });
        return current;
      }); 
      Promise.all(namePromises).then(function(names) {
        // use all names here.
      });
    

The only thing that remains is mapLimit - which is a bit harder to write - but
still not that hard:

    
    
      var queued = [], parallel = 3;
      var namePromises = ids.map(function(id) {
        // How many items must be complete before fetching the next?
        // The queued, minus those running in parallel, plus one of the parallel slots.
        var minComplete = Math.max(0, queued.length - parallel + 1);
        // when enough items are complete, queue another request
        // for an item, then get the item's name.
        return Promise.some(queued, minComplete)
          .then(function() {
            var download = getItem(id);
            queued.push(download);
            return download;
          }).then(function(item) {
            return item.name;
          });
      });
      Promise.all(namePromises).then(function(names) {
        // use all names here.
      });
      

Is a library needed? Probably, but only for mapLimit.

~~~
pjs67123
Awesome, looking forward to your guide.

