Working with Clojure, I discovered several issues with how promises interoperate. It made me wonder, what actually is a Javascript promise?
Apparently, there’s a whole website dedicated to explaining what a promise is. From it, we can figure a straightforward definition:
“promise” is an object or function with a
then
method whose behavior conforms to this specification. In Javascript,Promise.resolve(true) instanceof Promise
holds true, but that doesn’t mean it is the only acceptable promise. Studying Clojure’s promesa, I learned that anyone can implement a Promise-like object. After all, the only thing it needs to have is athen
method.
So, when writing code that can accept both an immediate value or a promise of one in JS, what do you do? How do you know a promise is a promise?
The answer is: you shouldn’t ever care about that.
If your function receives an immediate that might or might not be a promise, always turn it into a promise with Promise.resolve()
, i.e. instead of this:
|
|
do this:
|
|
Easy right? Well, apparently not.
While Promise.resolve()
is relatively cheap for immediates, it still allocates a promise object (obviously). The specification still dictates the creation of the microtask even for a known-resolved promise, thus await Promise.resolve(42)
will have to pay the penalty of that, which will be noticeable in the code optimised for performance.
A solution to that would be to see if the value is either a Promise, or a Thenable:
|
|
But, of course, it’s a rather rare occurrence, as the author of prom-client correctly notes.
Maybe we should stop inventing custom promises…