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()
structures often recall async “callback hell”, there’s no consistency
to APIs that return promises, and there’s no design patterns to introduce some
order. (If working with push notifications, for example, you’re likely to end up
with at least three Promise-returning constructions: a static property
(.ready
), a getter (.getSubscription()
) and a verb (.subscribe()
).)
One approach to improving this situation is to lean on ES6’s
yield
or ES7’s
await
and use Babel or
Traceur to transpile 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 resolves to
Since you never really need the promise and the value the promise resolves to at
the same time, give them the same name–they represent the same thing anyway,
and giving them completely separate names makes no sense. (Annotating the types
Hungarian-notation style might help, but it turns out that prepending or
appending p
or promise
to variable names looks silly.)
That is, if your promise is foo
, then the name of the argument should also be
foo
:
foo.then(function (foo) {
// ...
});
Similarly, a function like fetch()
does not return a fetchPromise
; it
returns a response
:
var response = fetch(...);
response.then(function (response) {
// ...
});
Eliminate Promise chaining with functions, objects–any which way you can
Promise hell usually isn’t quite as bad as callback hell, but it can certainly be hell-ish. For example, some Promise-based APIs you may be able to encapsulate common operations on a
Separate Promise code from non-Promise code
A lot of code mixes together logic and the boilerplate that goes with the Promise syntax. Try to avoid mixing the two by moving all the boilerplate somewhere else. (Encapsulating it inside an object might a viable choice.)
It’s possible 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 language as first class values. (That is, if you could use Promises wherever you would otherwise use values.) Is it possible to actually write code like this, by moving move the Promise-manipulation code somewhere else? If this is possible, is it otherwise a good idea?
printf
-style debugging of Promises
Here’s a simple function for console.log
-style debugging of Promises:
function 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);
user.then(...)
Remember that .then()
lambdas can return promises
Resolving a list of promises to arguments
Remember that you can attache multiple “listeners” to a Promise