I’ve been getting big into promises over the last year. I think the two best resources that I’ve learnt from today is Forbes Lindesay’s [talk at JSConf.EU 2013](https://www.youtube.com/watch?v=qbKWsbJ76-s) and Jake Archibald’s excellent [promise article on html5rocks](http://www.html5rocks.com/en/tutorials/es6/promises/).

There’s been some patterns that I use over and over so I wanted to share and document them.

Please note that the examples used are _mostly based on my real code, but have been simplified for demonstration purposes._

[I’ve published 38 videos for new developers, designers, UX, UI, product owners and anyone who needs to conquer the command line today.](https://training.leftlogic.com/buy/terminal/cli2?coupon=BLOG\&utm_source=blog\&utm_medium=banner\&utm_campaign=remysharp-discount)

Library of choice[](#library-of-choice)

Firstly I prefer to use the native implementation, and go bare bones. I’m sure they will be a time that I’ll want more than the native API has to offer, but I’ve not arrived there yet.

As a client side polyfill and the server side, in node-land, since promises are oddly not available natively, my preferred library is [then/promise](https://github.com/then/promise).

I’ve used [RSVP](https://github.com/tildeio/rsvp.js) in the past and heard decent things about [Bluebird](https://github.com/petkaantonov/bluebird).

RSVP feels like it’s mostly bare bones, but I learnt about promise.js' denodeify which converts a callback based function into a promise function which can be very useful.

Update @ 2014-11-19 15:30:00 RSVP does also have [denodeify](https://github.com/tildeio/rsvp.js/blob/master/lib/rsvp/node.js#L74) and Matt Andrews of The FT has released a [stand alone denodeify](https://www.npmjs.org/package/denodeify) module.

Clean shallow chains[](#clean-shallow-chains)

This means my initial promise code would look like:

writeFile(filename, content)
  .then(addDBUser)
  .then(dns)
  .then(configureHeroku)
  .then(function () {
    console.log('All done');
  })

This is easy if these are all my functions, but I can also do this with third party libraries via denodeify (a feature of the promise.js library, though most promise libraries have something similar) – turn a callback pattern function into a promise based function:

var writeFile = Promise.denodeify(fs.writeFile):

writeFile(filename, content)
  .then(addDBUser)

Though one place I’ve been caught out with denodeify is when the method relies on method’s context, which is most things as it turns out (fs is just a fluke that it’s methods don’t rely on the context), so make sure to bind as required:

var addUser = Promise
  .denodeify(model.user.add)
  .bind(model.user) // multi line for blog readability

Prebaking[](#prebaking)

You’ve already seen that I use bind, but I’ve also found that in some situations, I need to call a function with static arguments (i.e. not relying on the previous promise), just because it’s part of the promise chain.

I could do this:

writeFile(filename, content)
  .then(function () {
    return addUserToDb('rem', 'password', 'some-db');
  })

Or, what I’ve found I’m more inclined to do now is prebake the addUserToDb call with the static arguments:

var addUser = addUserToDb.bind(null, 'rem',
      'password', 'some-db');

writeFile(filename, content)
  .then(addUser)

This also allows me to code with the [shallow chains](#clean-shallow-chains) as above, because it (to me) feels a bit verbose to drop into a function just to return a promise straight back out that doesn’t depend on any unknown variable.

The thing to watch out for is if the function behaves differently if there’s more arguments, I have to cold call the promise.

Cold calling[](#cold-calling)

Disclaimer: this patterned is required due to my own prebaking patterns and attempts to (ironically) simplify. There’s a good chance you won’t need this!

When a function works both as a promise and using the callback pattern - it’s great, but I’ve been caught out in the past.

The way the function might work under the hood is something like (this pseudo code):

Heroku.prototype.post = function (slug, options, callback) {
  // do some async thing
  this.request(slug, options, function (error, data) {

    // ** this line is how the dual functionality works ** //
    if (callback) callback(error, data);

    // else do something with promise
  });

  // return some promise created some place
  return this.promise;
}

So post can be called either as a promise:

heroku.post(slug, opts).then(dostuff);

Or as a callback:

heroku.post(slug, opts, dostuff);

But gets messy when you do this:

function configureHeroku(slug) {
  // prebake heroku app create promise
  var create = heroku.post.bind(heroku,
    '/apps',
    { name: 'example-' + slug }
  );

  // prebake domain config
  var domain = heroku.post.bind(heroku,
    '/apps/example-' + slug + '/domains',
    { hostname: slug + '.example.com' }
  );

  // ** this is where it goes wrong ** //
  return create().then(domain);
}

The issue is when domain is called, it’s actually called with the prebaked arguments of the slug and options but also the resolved value from create() - so a third argument is received.

This third argument is the resolved result of create() which is treated as the callback argument and as a function object, so the code will try to invoke it - causing an exception.

My solution is to wrap in a cold call - i.e. a newly created function that calls my method with no arguments. Like bind once but then never allow any new arguments, also known as currying (here’s a simple demo of the [curry/partial/seal](https://jsbin.com/gopiqu/edit?js,console) type-thing):

function coldcall(fn) {
  return function () {
    fn();
  };
}

function configureHeroku(slug) {
  // prebake heroku app create promise
  // ...


  // ** now it works ** //
  return create().then(coldcall(domain));
}

Note: you can do this using currying, i.e. [lodash.curry](https://lodash.com/docs#curry).

Now the domain call works because it’s invoked preventing any extra arguments being added.

Throw over explicit reject[](#throw-over-explicit-reject)

Instead of:

// compare password & input password
return new Promise(function (resolve, reject) {
  bcrypt.compare(input, password, function (error, result) {
    if (error || !result) {
      // reject and early exit
      return reject(error);
    }

    resolve(result);
  });
});

I’ll throw instead of reject:

// compare password & input password
return new Promise(function (resolve) {
  bcrypt.compare(input, password, function (error, result) {
    if (error) {
      throw error;
    }

    if (!result) {
      throw new Error('Passwords did not match.');
    }

    resolve(result);
  });
});

This might be a little controversial. In fact, when I threw this out to twitter, most people came back with something like:

Reject whenever possible, it’s more performant because throw breaks the stack.

This may well be so, but there’s a few key benefits to my code when I throw:

  1. I’m used to error first handling, and quite often I’ll accidently recieve reject as the first argument, which leads to much confusion. This way, I only ever accept resolve as my argument. There’s also issues where "reject" and "resolve" as words are visually similar, which has also lead to confusion when they’re the wrong way around!

  2. I don’t have to remember to return reject. I’ve seen code that doesn’t return on reject, and it then goes on to resolve with a value. Some libraries fulfill, some reject, some throw new errors. Throwing the error avoids this entirely.

  3. This is also consistent with the way I’ll deal with errors inside of subsequent then calls:

// compare password & input password
utils.compare(input, password)
  .then(function () {
    if (!validUsername(username)) {
      throw new Error('Username is not valid');
    }
    // continues...
  })
  .then(etc)

Jake also chimed in with a couple of useful replies:

reject is supposed to be analogous to throw but async. So reject what you’d throw (which is usually an error)

Then linked to his [post](http://jakearchibald.com/2014/es7-async-functions/) with "in ES7 async functions reject is throw". This also reinforces that you want to reject with a real error, not a string.

Always end with a catch[](#always-end-with-a-catch)

It’s not uncommon for me to be testing a http request with a promise, and it just never returns…​

The issue is that the promise has been rejected somewhere and it’s not been caught. So I always end with a catch. Even if it’s a dump to the console, that way I know something failed.

writeFile(filename, content)
  .then(addDBUser)
  .then(dns)
  .then(configureHeroku)
  .then(function () {
    console.log('All done');
  })
  .catch(function (error) {
    // do something with error
    console.log(error.stack);
    handle(error);
  });

This final catch lets me see the full stacktrace as to what went wrong, and importantly that something did go wrong (see blog comments for discussion about this).

Note: .catch() is only in the ES6 spec and doesn’t appear in Promises/A+ so some library implementations are missing .catch() support (as I’ve found with [mongoose](http://www.mongoosejs.com/) as it depends on [mPromise](https://www.npmjs.org/mpromise) library).

Recap[](#recap)

So that’s it:

  • Shallow chains

  • Prebaking where I can and cold calling if neccessary

  • Always throw

  • Always catch

Pretty simple. I’d be interested to hear what patterns are emerging in your workflow too.

Comments

Lock Thread

Login

Add Comment[M ↓   Markdown]()

[Upvotes]()[Newest]()[Oldest]()

![](/images/no-user.svg)

Vitaly Tomilov

0 points

8 years ago

My favourite promise patterns that are missing everywhere: [https://github.com/vitaly-t…​;](https://github.com/vitaly-t/spex)

![](/images/no-user.svg)

Vitaly Tomilov

0 points

8 years ago

These are the patterns I had to design: [https://github.com/vitaly-t…​;](https://github.com/vitaly-t/spex)

![](/images/no-user.svg)

Raine Revere

0 points

9 years ago

Another approach to the curry/partial/seal technique that can be applied in your coldcalling pattern is to use an aritize function. It decouples argument-limiting (changing the arity of the function) from currying.

return create().then(aritize(domain, 0));

![](/images/no-user.svg)

Christian Alfoni Jørgensen

0 points

9 years ago

Hi, thanks for sharing! I have been using Q ([https://github.com/kriskowa…​;](https://github.com/kriskowal/q)) mostly, but wanted to try out the native Promise. But I got into this situation very quickly:

{ getArticle: function (id) { return new Promise(function (resolve, reject) { id = new ObjectID(id); mongodb.collection('articles').findOne({_id: id}, resolveDatabaseResponse(resolve, reject)); }); } }

I found myself wanting a general database response handler. I have to pass two arguments which kinda sucks. I like Q syntax better, it just looks a lot cleaner:

{ getArticle: function (id) { var deferred = Q.defer(); id = new ObjectID(id); mongodb.collection('articles').findOne({_id: id}, resolveDatabaseResponse(deferred)); return deferred.promise; } }

Just looking at this now I found:

{ getArticle: function (id) { var deferred = Q.defer(); id = new ObjectID(id); mongodb.collection('articles').findOne({_id: id}), deferred.makeNodeResolver()); return deferred.promise; } }

Even cleaner.

Well, I guess this got more of a sharing comment than question comment :-) Any experience handling this kind of stuff?

![](/images/no-user.svg)

Scott Rippey

0 points

9 years ago

I, too, like the throw pattern, instead of reject. Although, I, too, am constantly defending it! Then, I wanted to take it a step further, and replace that "resolve" with return. So here’s a pattern I like: Promise.resolve().then( /* here, I can throw or return anything, sync or async! */ ) Of course, I have to defend this even more!

![](/images/no-user.svg)

ElBobbio

0 points

9 years ago

I thought ES6 .catch() simply sugar for:

.then( undefined , function( rejectValue ) { } )

meaning, you substitute that for .catch()?

![](/images/no-user.svg)

rem

0 points

9 years ago

It is. But sugar here promotes good practises, whereas, IMHO, the es6 version would lead to the catch being left out.

![](/images/no-user.svg)

Matt

0 points

9 years ago

Thanks for the mention for denodeify. Just wanted to share another problem / an alternative to “always end with a catch”.

If you want to have error aggregation (e.g. Sentry) to collect all the uncaught errors in your application, heavy use of promises is going to suppress and hide them all.

Therefore we are standardising on “always end with an equivalent of Q’s .done()”… Which is effectively the equivalent of:-

foo() .then(bar) .catch(function(err) { setTimeout(function() { throw err; }); });

It’s pretty easy to wrap that up into a patch on the global Promise (if you have the luxury of only a single promise implementation floating around) or you could do something like this:-

foo() .then(bar) .catch(thrower);

This allows uncaught errors to break out of the promise flow and be catchable by a global error handler (window.onerror, process.on('uncaughtException')) but I really hate this solution and wish there were a cleaner way to do it that meant that you didn’t need to remember every time you use promises to finish in a certain way. Had a Twitter debate about this with my colleague Ada, @jaffathecake:disqus & Oliver Joseph Ash — which is here: [https://twitter.com/andrews…​;](https://twitter.com/andrewsmatt/status/532569644885102592).

![](/images/no-user.svg)

jaffathecake

0 points

9 years ago

If you’re catching for the purposes of logging, I’d always rethrow the error unless I was intending on recovering from the error.

`\`\ try {\ whatever();\ }\ catch(e) {\ console.error(e);\ }

blah();

var p = whatever().catch(function(e) {\ console.error(e);\ });

p.then(function() {\ return blah();\ });

try {\ whatever();\ }\ catch(e) {\ console.error(e);\ throw e;\ }

blah();

var p = whatever().catch(function(e) {\ console.error(e);\ throw e;\ });

p.then(function() {\ return blah();\ });\ `\`

![](/images/no-user.svg)

rem

0 points

9 years ago

Sure. And it depends on what I’m doing too. Whilst I’m developing, I might want to crash the app to see what’s causing the issue, or I might want to log and stay up whilst I then handle the error.

The pattern wasn’t particularly to show how I’d log the error, but rather than I always end on a catch so I’m forced to handle the error in some way.

![](/images/no-user.svg)

Malte Ubl

0 points

9 years ago

The "Always end with a catch" pattern in probably not good advice. One should only add a catch if and only if one had wrapped the same program in a try-catch-block in a synchronous program.

If a catch is necessary to show the error on the console then that is a bug in the promise implementation; working around that in user code is bad because another party may add a catch block that may actually be handling the error but now it still goes to the console and your example just prints the stack but fails to print the error message – the library just can do a much better job at this.

Some promise libraries ship with this "bug" because in a purist view of promises (probably involving the word monad) it is not a nice that this requires adding catch handlers in the same execution stack as the promise was created – but real world programming has shown that there is absolutely nothing worse for programmer’s productivity but an error that was thrown but then just "eaten" by the system instead of notifying the programmer. Basically you sit in front of a machine and it doesn’t work, but it doesn’t tell you why.

This is why Chrome changed the behavior: Uncaught promise errors will go to the console (works in Canary, apparently not yet in stable). I don’t have a good list of promise libraries that do the right thing, but the one I work on does :) [https://github.com/google/c…​;](https://github.com/google/closure-library/blob/master/closure/goog/promise/promise.js)

Another thing that goog.Promise does to help debugging is that it "throws" every explicit call to reject ([https://github.com/google/c…​;](https://github.com/google/closure-library/blob/master/closure/goog/promise/promise.js#L162)). The error is immediately caught and ignored – but if you set your DevTools to "break on caught exceptions" it will also break for rejects – which is what you want since they are semantically equivalent to throws.

[Commento](https://commento.io)