HAYCORN — 29 March 2015

Promise Patterns

Promises are still pretty new, and whilst their place in the Javascript world is by this point pretty secure (most of the newer JS APIs are Promise based), the ways in which they’re used are still evolving: the clunky syntax and nested .then() struc­tures often recall async “callback hell”, there’s no con­sis­tency to APIs that return promises, and there’s no design pat­terns to in­tro­duce some order. (If working with push notifications, for example, you’re likely to end up with at least three Promise-returning constructions: a static prop­erty (.ready), a getter (.getSubscription()) and a verb (.subscribe()).)

One ap­proach to im­prov­ing this sit­u­a­tion is to lean on ES6’s yield or ES7’s await and use Babel or Traceur to tran­spile future Javascript into the Javascript of today, but there’s a few things you can do without leaving browser-compatible Javascript.

Use the same name for the promise and the name of the value the promise re­solves to

Since you never really need the promise and the value the promise re­solves to at the same time, give them the same name–they rep­re­sent the same thing anyway, and giving them com­pletely sep­a­rate names makes no sense. (Annotating the types Hungarian-notation style might help, but it turns out that prepend­ing or ap­pend­ing p or promise to vari­able names looks silly.)

That is, if your promise is foo, then the name of the ar­gu­ment should also be foo:

foo.then(function (foo) {
 // ...

Similarly, a func­tion like fetch() does not return a fetchPromise; it returns a response:

var re­sponse = fetch(...);
response.then(function (response) {
 // ...

Eliminate Promise chain­ing with functions, objects–any which way you can

Promise hell usually isn’t quite as bad as call­back hell, but it can cer­tainly be hell-ish. For example, some Promise-based APIs you may be able to en­cap­su­late common op­er­a­tions on a

Separate Promise code from non-Promise code

A lot of code mixes to­gether logic and the boil­er­plate that goes with the Promise syntax. Try to avoid mixing the two by moving all the boil­er­plate some­where else. (Encapsulating it inside an object might a viable choice.)

It’s pos­si­ble that it will help to convert simple values into Promises:

Try to write the code you’d write if Promises were built in to the language

When working with Promises, try to imagine what the code would look like if Promises were built in to the lan­guage as first class values. (That is, if you could use Promises wher­ever you would oth­er­wise use values.) Is it pos­si­ble to ac­tu­ally write code like this, by moving move the Promise-manipulation code some­where else? If this is possible, is it oth­er­wise a good idea?

printf-style de­bug­ging of Promises

Here’s a simple func­tion for console.log-style de­bug­ging of Promises:

func­tion DEBUG(s, p) {
 p.then(console.log.bind(console, s, "RESOLVED"), console.warn.bind(console, s, "REJECTED"));
 return p;

Use it like this:

var user = foo.getUser(); // returns a Promise
DEBUG("user = ", user);

Remember that .then() lambdas can return promises

Resolving a list of promises to arguments

Remember that you can attache mul­ti­ple “listeners” to a Promise