-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Switch from "Thenable Assimilation Procedure" to "Promise Resolution Procedure" #89
Conversation
1. If/when `x` is rejected, reject `promise` with the same reason. | ||
1. Otherwise, if `x` is an object or function, | ||
1. Let `then` be `x.then`. [[4.5](#notes)] | ||
1. If retrieving the property `x.then` results in a thrown exception, fulfill `promise` with `x`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't sure whether to nest this or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems ok to me not to nest it.
I like this change a lot, @domenic. Even though it seems like just terminology, I think not introducing a new concept of "assimilation" into the spec is a good thing. This may also help the "resolve"/"resolved" teminology situation a bit. |
Awesome :). Indeed, I was thinking of adding definitions for "settled" and "resolved", but couldn't find a great place to put them. |
One consequence of this procedure, or rather how it deals with Nonetheless, I like it. |
@novemberborn Yep, that's correct. Internally, the duck type test followed by a second access to Interestingly, this means that a public |
Updated with the other exception handling strategy. Will merge in a few days if there are no objections, and re-start the ratification procedure. |
I've been a bit busy so haven't managed to follow this discussion very closely. The only slight issue I have with it is that when we introduce ES6 proxies, it might be very reasonable to construct a proxy which throws when you attempt to access any property that's not defined, which would lead to a rejection here, when you probably really want it to lead to the object not being treated as a promise. |
I'm not saying it's necessarily worth changing things, but it's worth considering. |
(I implemented the previous wording of the procedure yesterday.) I believe there is a distinction between determining whether a given value is a thenable, and adopting the state of potentially unreasonable thenables.
Observation should not lead to rejection. If we can't determine the type of the If we are dealing with a thenable, however, we need to be able to deal with unreasonable thenables which:
The first two scenarios are easily dealt with. The third means the promise remains pending, which we can interpret as the thenable remaining pending. In the fourth scenario we drop the error. The fifth scenario is interesting. It seems reasonable to assume If we really cared about not dropping thrown errors we would still reject the promise in the fourth scenario. Similarly with the promises-aplus/constructor-spec#18 proposal. |
@novemberborn I agree that (4) drops a thrown error. However, this does not contradict the text of mine you quoted. There is no "natural promise to break", since the returned promise has already been resolved by the call to resolvePromise or rejectPromise. But I take seriously your
This makes sense too. I am now truly undecided and puzzled. |
I'd almost say that's cheating ;-) If a "natural promise to break" is only a non-resolved promise then why are we so concerned about not dropping errors? I want to avoid leaving promises in a hard-to-debug pending state because Scenarios in which an error would otherwise be dropped can be handled by reporting infrastructure in the promise libraries themselves. |
It's OK to not report an exception/rejection when it's been handled. In this case, we can handle it by assuming the object is not a real thenable. That's a totally acceptable course of action. Alternatively we could reject the promise. I'm definitely in favour of handling it by assuming the object is not a real thenable, because creating a thenable that sometimes throws when you try and access The advantage I can see to causing the rejection would be that if you were creating some weird proxying promise like object you may well end up accidentally throwing errors when people accessed |
I think it is not wise to support inconsistent (buggy?) proxies, as it's not wise to support bad thenables. So rejecting in case a |
Nobody's suggesting anything other than rejecting when It's only a thenable if we make the check for a |
Maybe I was not clear enough. By this change, you have to retrieve |
Ah, I'm fine with rejecting if a second call to get |
I am ok with rejecting when |
Ah yes. If |
Also, how about defining an |
This is nonnegotiable, and Q will certainly be adopting this algorithm. It follows the same behavior as the ES5 spec in many places.
This is not possible, precisely because determining if something is a thenable cannot be formally separated from the resolve algorithm---otherwise |
I certainly understand that having an
Can you please be more specific of which behaviors in ES5 you are referring?
And is the behaviour of retrieving |
I know you have in the past justified questions like this by appealing to your laziness, but I'm going to have to kindly ask you to not comment on the Promises/A+ repositories if you can't do the minimum background reading first. For example, the linked issues in the original post. It wastes everyone's time, and while I was OK with repeating myself once or twice for your benefit, it has continually derailed Promises/A+ threads as I need to explain things that have already been explained elsewhere. Sorry to be harsh. Anyway, here's the post you didn't read, in #88 (comment), which is linked in the original post:
No, it is not. The entire Promise Resolve Procedure will be performed in a separate tick. |
I am on a trip and my mobile app was not showing #nn as links. I am sorry for missing them and I am even more sorry for giving the wrong impression of expecting from anyone to repeat himself. |
Ok. Is it also ok to stay on the same tick in case Is there any intention in the future to specify which parts (besides callbacks) are expected to run in separate ticks? |
Yes, I can't see anything wrong with that. That kind of performance benefit was one of the primary use cases of allowing a separate clause for promises.
If we ever specify assimilation (i.e. specify |
Agree: a trusted promise is just that, trusted. IMHO, an implementation can assume that it doesn't need to force a new stack to protect itself from its own promises. |
Thanks. My concern (that I missed to specify) was if it would introduce unexpected inconsistency with the case where |
This helps specify how you should get a reference to the `then` method, test it, and then call that same reference, as discussed in #88. I think it also makes the spec rather more elegant.
This was prompted by #87 and #88, and in particular the discussions about how you should only retrieve a reference to
then
once, and then call that same reference.This necessitated refactoring from "if
x
is a thenable, run theAssimilation(thenable, promise)
; otherwise, fulfillpromise
withx
"---which necessarily seems to involve a two-step process---to simply "runResolve(promise, x)
." I think it turned out rather nicely, actually.A second commit tries to resolve the question of exception handling by treating something with a throwing getter for
then
as a non-thenable. It seems right to me, but I am willing to be persuaded in the other direction. I included it as a separate commit specifically because the refactoring is separate from the exact approach of how we handle throwing getters forthen
.You can see the end result here.