(Related but not quite the same: JS Promises: Fulfill vs Resolve)
I've been trying to wrap my head around Javascript promises, and I'm struggling with the basic notions of resolve and resolved, vs. fulfill and fulfilled. I have read several introductions, such as Jake Archibald's, as well as browsing some relevant specs.
In States and Fates (not quite an official spec, but referenced as an authoritative document written by one of the spec authors), fulfilled is a state while resolved is a "fate" (whatever that is -- but they're clearly distinct):
Promises have three possible mutually exclusive states: fulfilled, rejected, and pending.
- A promise is fulfilled if
promise.then(f)
will call f "as soon as possible."
and
A promise is resolved if trying to resolve or reject it has no effect, i.e. the promise has been "locked in" to either follow another promise, or has been fulfilled or rejected
In particular, resolved encompasses both fulfilled and rejected (and locked in). The "opposite" (or directly corresponding function) to reject is fulfill, not resolve; resolve includes reject as one of its possibilities.
Yet the spec refers to the first argument to the then()
method (or its corresponding abstract concepts) using both fulfill and resolve:
25.4: A promise p is fulfilled if p.then(f, r) will immediately enqueue a Job to call the function f.
25.4.1.1: [[Resolve]] A function object The function that is used to resolve the given promise object.
25.4.1.3: Set the [[Promise]] internal slot of resolve to promise. Set the [[AlreadyResolved]] internal slot of resolve to alreadyResolved. [Then immediately after, reject is used in an exactly corresponding way.]
25.4.5.3: Promise.prototype.then ( onFulfilled , onRejected )
Maybe one of the most crucial is
25.4.4.5 Promise.resolve ( x )
which MDN describes as follows:
The Promise.resolve(value) method returns a Promise object that is resolved with the given value. If the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise the returned promise will be fulfilled with the value.
There is no mention of the Promise.resolve()
method having the potential to reject. Furthermore, there is a Promise.reject()
method, but no Promise.fulfill()
method. So here, the counterpart to reject is resolve, instead of fulfill.
Granted, there might be no guaranteed correlation between the "fate" term resolved, and the method (or verb) resolve. But it would be (is?) really misleading and confusing to have resolve()
put a promise into a specifically fulfilled state, when the terms fulfilled and resolved have carefully been defined to have distinct meanings.
Is that what has happened here... the right hand didn't know what the left hand was doing, and we ended up with the documents that are supposed to be the guiding lights of the movement using terms in inconsistent ways? Or is there something I'm missing, and resolve is actually a more appropriate term than fulfill for what the resolve()
method does?
I don't mean to come across as critical of the document authors. I understand how, with a widely-distributed group, over history, it's difficult to get all the terms to be used consistently across all documents. My purpose here, in digging into the terminology and phrasing of these documents, is to understand the terms accurately -- which includes knowing the limits of how precisely terms like fulfill and resolve can really be distinguished. Jake Archibald admits that he sometimes gets the terms mixed up. That's a very helpful admission to noobs like me who are trying to make sense of terminology! Thank you, Jake, for being vulnerable. :-) My purpose in asking this question is to find out, which definitions or usages of those terms are reliable? Or should I conclude that resolve is sometimes used specifically to mean fulfill, and sometimes fulfill/reject/lock in, even in the most authoritative documents?
Promise resolve() method: If the value is a promise then promise is returned. If the value has a “then” attached to the promise, then the returned promise will follow that “then” to till the final state. The promise fulfilled with its value will be returned.
resolve("aaa") is the same as return Promise. resolve(Promise. resolve("aaa")) - since resolve is idempotent calling it on a value more than once has the same result.
Fulfilled is a state of a Promise. It means that the promise has been resolved and now has its resolved value (using the internal resolve function). The operation represented by the promise has been completed successfully.
I'm struggling with the basic notions of resolve and resolved, vs. fulfill and fulfilled.
Have a look at What is the correct terminology for javascript promises. Yes, they're sometimes mixed up, but let's try to ignore that.
Yet the spec refers to the first argument to the
then()
method (or its corresponding abstract concepts) using both fulfill and resolve. Did we end up with the documents that are supposed to be the guiding lights of the movement using terms in inconsistent ways?
No, there is no inconsistency here, the terms in the spec are accurate.
resolve is not the opposite of reject, and the onFulfilled
callback does not exactly correspond to resolving.
Or is there something I'm missing, and resolve is actually a more appropriate term than fulfill for what the
resolve()
method does?
Yes. The problem is that you can resolve with a promise (or in general, a thenable, i.e. any object with a then
method), and instead of fulfilling with that object the resolved promise will try to fulfill with the thenable's result. Or when the thenable has (will have) an error, it will reject with that as the reason.
There is no mention [in MDN] of the
Promise.resolve()
method having the potential to reject.
Actually there is: "the returned promise will "follow" that thenable, adopting its eventual state". If that eventual state is the error state, then the returned promise will reject as well.
There is a
Promise.reject()
method, but noPromise.fulfill()
method. So here, the counterpart to reject is resolve, instead of fulfill.
Yes, ES6 promises are lacking a Promise.fulfill
method. This is a bit inconsistent and confusing at first, but was done for a good reason: It prevents you from having a promise that is fulfilled with another promise. You can only resolve ES6 promises, and when you pass in a promise it will take its result not the promise object by itself.
This is pretty useful, but can be pretty inconvenient as well. There are libraries that do it better and allow this case, they're so-called "algebraic promises" (which you can reason about a lot better). Creed is a good example of that, and its Promise.of
method is a real counterpart to Promise.reject
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With