-
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
Settle reader.[[closedPromise]] before performing close/error steps of read requests #1102
Settle reader.[[closedPromise]] before performing close/error steps of read requests #1102
Conversation
Calling resolvePromise() or rejectPromise() on a promise that was created with either promiseResolvedWith() or promiseRejectedWith() would throw an error, since the expected resolve or reject method did not exist in the side table. Resolving or rejecting an already resolved/rejected promise should be a no-op, so we fix these helpers by returning immediately if we already resolved/rejected the promise earlier.
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.
LGTM. As shown in https://github.com/web-platform-tests/wpt/pull/27236/files this is a change for all implementations though, so we'll want bugs filed at the very least.
@ricea can you check this out and see if the change makes sense to you, and is worth doing in Chromium? If you as an implementer think that maybe we shouldn't bother with the churn, then that's also a worthwhile sign...
As you've found, it is observable, so please remove this sentence. 😄
I believe the intent was to try to ensure that a promise in the standard would never be resolved or rejected more than once. In practice, we've never managed to completely eliminate such errors, so all implementations have to guard against them anyway. On balance, I think it's still worth trying to avoid multiple resolves / rejects in the reference implementation and standard, since it helps us catch some kinds of bugs. |
I liked the old behaviour of resolving |
Good point. Updated the PR description. 🙂
Would it make sense for the promise helpers in the reference implementation to assert that the promise is still pending? That is, change these lines in - if (promiseSideTable.get(p).stateIsPending === false) {
- return;
- }
+ assert(promiseSideTable.get(p).stateIsPending === true); We could do this only in the reference implementation, just to help catch bugs. Or would we also want to add normative asserts everywhere we resolve or reject a promise in the specification text? |
Yes, that would be good. Could you do it in this PR?
I think we shouldn't make it normative in the specification text, because we've so far always found cases where we failed to preserve the invariant. @domenic may have a different opinion. |
I agree with reference implementation asserts (probably with a comment) and no spec changes. I kind of thought in this scenario the double-resolve was unavoidable, so the assert would fail? But I guess I missed something. |
…es that are still pending
Nope. At the start of We now swap the order around: first change the state to |
There is an alternative solution which retains the old behavior, i.e. resolving
But you'd still have the (kind of weird) situation where I think this alternative solution is more difficult to understand and maintain than the current solution. I still prefer the current one. 😁 |
Yes, I prefer the current one too. The alternative solution is too complex for me to have confidence that it is right. |
Alright, let's land this. I'll merge the WPT PR; @MattiasBuelens would you be able to roll the tests one last time and then file browser bugs? As editor, I'm willing to skip gathering affirmative implementer interest for this sort of minor barely-observable internal bugfix, on the reasoning that we can revisit if there's any pushback (which seems highly unlikely). As long as we have one implementer (viz. @ricea) saying this is worthwhile. |
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.
lgtm from me too.
Sure thing! I'll roll WPT after the tests PR has landed. 🙂 |
…r steps of read requests Follows whatwg/streams#1102.
Implementation bugs are filed, links are in the PR description. Ready to merge. |
… before performing close/error steps of read requests, a=testonly Automatic update from web-platform-tests Streams: settle reader.[[closedPromise]] before performing close/error steps of read requests Follows whatwg/streams#1102. -- wpt-commits: 7e94a4bcb5bd6808e08ed8db46fa63751543db52 wpt-pr: 27236
… before performing close/error steps of read requests, a=testonly Automatic update from web-platform-tests Streams: settle reader.[[closedPromise]] before performing close/error steps of read requests Follows whatwg/streams#1102. -- wpt-commits: 7e94a4bcb5bd6808e08ed8db46fa63751543db52 wpt-pr: 27236
… before performing close/error steps of read requests, a=testonly Automatic update from web-platform-tests Streams: settle reader.[[closedPromise]] before performing close/error steps of read requests Follows whatwg/streams#1102. -- wpt-commits: 7e94a4bcb5bd6808e08ed8db46fa63751543db52 wpt-pr: 27236 UltraBlame original commit: 20f8538ad6904319bdc6519519173023ebab1f2b
… before performing close/error steps of read requests, a=testonly Automatic update from web-platform-tests Streams: settle reader.[[closedPromise]] before performing close/error steps of read requests Follows whatwg/streams#1102. -- wpt-commits: 7e94a4bcb5bd6808e08ed8db46fa63751543db52 wpt-pr: 27236 UltraBlame original commit: 94c2eaea68702cd0a923a39860c69bb2bd62cb3f
… before performing close/error steps of read requests, a=testonly Automatic update from web-platform-tests Streams: settle reader.[[closedPromise]] before performing close/error steps of read requests Follows whatwg/streams#1102. -- wpt-commits: 7e94a4bcb5bd6808e08ed8db46fa63751543db52 wpt-pr: 27236 UltraBlame original commit: 20f8538ad6904319bdc6519519173023ebab1f2b
… before performing close/error steps of read requests, a=testonly Automatic update from web-platform-tests Streams: settle reader.[[closedPromise]] before performing close/error steps of read requests Follows whatwg/streams#1102. -- wpt-commits: 7e94a4bcb5bd6808e08ed8db46fa63751543db52 wpt-pr: 27236 UltraBlame original commit: 94c2eaea68702cd0a923a39860c69bb2bd62cb3f
… before performing close/error steps of read requests, a=testonly Automatic update from web-platform-tests Streams: settle reader.[[closedPromise]] before performing close/error steps of read requests Follows whatwg/streams#1102. -- wpt-commits: 7e94a4bcb5bd6808e08ed8db46fa63751543db52 wpt-pr: 27236 UltraBlame original commit: 20f8538ad6904319bdc6519519173023ebab1f2b
… before performing close/error steps of read requests, a=testonly Automatic update from web-platform-tests Streams: settle reader.[[closedPromise]] before performing close/error steps of read requests Follows whatwg/streams#1102. -- wpt-commits: 7e94a4bcb5bd6808e08ed8db46fa63751543db52 wpt-pr: 27236 UltraBlame original commit: 94c2eaea68702cd0a923a39860c69bb2bd62cb3f
At least two implementations (#1100, MattiasBuelens/web-streams-polyfill#66) have made the (incorrect) assumption that
reader.[[closedPromise]]
will only be resolved or rejected if the promise is still pending. This is currently not the case: an async iterator may release its lock (and rejectreader.[[closedPromise]]
) right before the stream tries to resolve that same promise again.With this PR, we now resolve or reject
reader.[[closedPromise]]
before going through all pending read requests and running their close or errors steps. This ensures that the stream is already done with all of its own state updates, and the read request's steps can observe and manipulate the "final" state of the stream. Thus, when the async iterator releases its lock, it will replace the[[closedPromise]]
with a newly rejected promise instead.This is a small but observable change for both web authors and other specifications:
reader.closed
will resolve withundefined
beforereader.read()
resolves with{ done: true, value: undefined }
.reader.closed
is already resolved (see comment on #1100).There was also a small bug in the reference implementation of the WebIDL promise helpers. Calling
resolvePromise
orrejectPromise
on a promise created withpromiseResolvedWith
orpromiseRejectedWith
would throw an error (such as "promiseSideTable.get(p).resolve
is not a function"). If we attempt to resolve or reject a promise that is already resolved or rejected, we should do nothing instead.At least two implementers are interested (and none opposed)(skipped):(See WHATWG Working Mode: Changes for more details.)
Preview | Diff