-
Notifications
You must be signed in to change notification settings - Fork 161
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
Add ReadableStreamDefaultControllerHasBackpressure operation and use it in TransformStream #767
Conversation
The TransformStream implementation currently looks at desiredSize to get an approximation of whether there is backpressure on the readable side or not. This is fragile and not really clean enough for standardisation. Add an internal "HasBackpressure" polymorphic method to the ReadableStream*Controller classes to permit TransformStream to determine whether there is backpressure directly.
Bikeshedding welcome. |
A couple of questions to spur discussion: Should this be an exported abstract operation rather than a polymorphic method? Does it matter? Should this be a public operation? Alternatively, should ReadableStream*Controller have a "ready" promise which provides the functionality of TransformStreamReadableReadyPromise? |
+1 on the general idea. There are a lot of changes here in the semantics, as the *ShouldCallPull abstract ops are much more in-depth, but in general it seems like the new semantics are better and more likely to cover edge cases. Speaking of those edge cases, it might be worth writing some tests to cover them. E.g. do steps 1-5 of https://streams.spec.whatwg.org/#readable-stream-default-controller-should-call-pull ever cause us to return early? Can we trigger that from a test?
Since it's polymorphic, that seems harder. I'm not sure what you mean by exported, but it seems unlikely, as this is somewhat of an implementation detail.
Heh, then the controllers really would look like writable streams... I don't think it's necessary, because I can't see how an underlying source would use it. Maybe if we didn't have pull() {}, but only start() {}, then you could use that promise to implement pull() {}. But we have pull(), which takes care of this use case, I think. |
Replace the polymorphic HasBackpressure method with a non-polymorphic ReadableStreamDefaultControllerHasBackpressure method.
Hard-code it, and take advantage of the invariant to simplify the start() method for TSReadableSource.
The user-visible behaviour change is one extra microtask before the first transform() is called when starting without backpressure. I think. Counting microtask iterations is tricky. Testing the number of microtask iterations is even trickier, so I'm not going to try. We make up for the extra call to pull() at startup by avoiding unnecessary calls to pull() when a read() is in process, so on balance it works out well. In #777 I argue for always starting with backpressure by default, which would make this difference even less consequential. This means there isn't anything I can test here. However, thanks to your hint I noticed that calling HasBackpressure before start() has completed will always return true, so I just hardcoded that value, which then let me simplify TSDefaultSource's start() method. When a close or error is triggered by the TransformStream itself, it always sets As part of my work in in restructuring the TransformStream implementation, I realised that the The benefit of having a |
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.
Now this is a nice simplification.
If you're confident this doesn't need any test changes, then please go ahead and merge :). Maybe the commit message can explain some of the things discovered here.
The TransformStream implementation currently looks at desiredSize to get
an approximation of whether there is backpressure on the readable side
or not. This is fragile and not really clean enough for standardisation.
Add an abstract operation ReadableStreamDefaultControllerHasBackpressure
which reflect the ReadableStream's own notion of whether there is
backpressure. Use it in TransformStream to accurately detect when an
enqueue() operation has filled the queue.
Since ReadableStream always considers itself to have backpressure until
the underlying source start() method completes, use the same convention
in TransformStream. This simplifies some logic.