-
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
New proposal for byte stream uses cases #289
Comments
I have been investigating an idea similar to yours. That's exposing WritableStream (stream for feeding) and ReadableStream (output emitter) on the ReadableByteStream. Your read() has the same signature as ReadableStream (object stream), but how piping between object stream and byte stream would be like? I think we should list what we mean by "compatibility with object stream" concretely and prototype how it'll be like. Does Just a naming preference, but I prefer |
Definitely agree. We don't even have a design for WritableByteStream yet :-/. We need to get on this. I will start trying to draw up the landscape tomorrow.
I think more like the latter. In this way a ReadableByteStream is like a ReadableStream with HWM = 0 that always respects backpressure and doesn't proactively fill up the queue.
Yes, I think that is better. wait() was originally there for symmetry with writable stream but I think it was largely a false symmetry from when we were more naive. OK. I have a lot of work to do tomorrow. I will try to write up examples of the entire ecosystem: readable streams, writable streams, exclusive readers, exclusive writers, byte versions of each of these four, and with both pull and push underlying sources (i.e. fread-style and epoll-style). If we don't discover a fatal flaw based on the examples we can start prototyping the readable side to make sure that exclusive readers are not too complex. If they are too complex, we can consider making pipeTo magical, as per original #241. Actually, maybe we should consider just making pipeTo magical to start with. Then we could introduce exclusive readers later to explain pipeTo. It might be tricky to do backward-compatibly (e.g. introducing a new state value seems possibly hostile). But it's worth considering. |
Are these correct? If so, I'm not sure if a user code expecting ReadableStream can work with ReadableByteStream - It may consume unnecessarily large memory. |
@yutakahirano that's a good point :(. Maybe it is OK, since it is not "normal" to call wait() many times. And we would probably store any extra buffers so that if you do In that case there's another possibility, which is the |
I wrote out a pretty long exploration of readable byte streams today. I didn't get to the other parts I planned quite yet. But it does cover, in a lot more detail than done previously, how both file- and socket-backed readable byte streams would work, and how generic readable stream processors can transparently use readable byte streams. It is based on the proposal in the OP, although I adopted @tyoshino's suggestion of naming the method https://gist.github.com/domenic/65921459ef7a31ec2839 I'd really appreciate a read-through. The issues noted in "Reading a byte stream into ArrayBuffers" are interesting, and I am curious how bad they are in practice. |
Domenic, what's the practical reason to shrink the given ArrayBuffer to correctlySizedAB? This means that at least when reading the last bytes of the resource, we'll often have to return a shrunk buffer to the pool. How about transferring the given ArrayBuffer for detaching but keep the size as-is and create a view to represent the region? |
@tyoshino hmm that is an interesting idea. I forgot that we had that trick up our sleeve, of packing up a byte length + a buffer into a single typed array. So people would access the underlying buffer with |
@tyoshino I am now convinced your idea is 100% necessary since the example I will update the gist with your idea instead. Also I had another idea which is to combine wait() and read() into a single async read with an optional argument. It seems OK but not great. |
Right. ArrayBufferView can be just used as a tuple of offset, size and buffer. Simple and powerful. I summarized scattered discussion into some comments at #253. Feel free to fix/add. |
Rolling this into the larger meta-issue at #253. |
As recently discussed in #253 and #288 there are several open issues with our current design for readable byte streams. The biggest ones are:
At the same time I think it is important that, as a guiding principle, we try to make readable byte streams deviate from other readable streams as little as possible, in author-facing interface. The entire point of streams as a primitive is to have a shared abstraction useful across lots of code, that many people build libraries on top of. Those libraries should ideally work just as well with readable byte streams as they do readable streams, without any extra work needed. That is why I have continually insisted that ReadableByteStream support the ReadableStream interface. This also is what motivated #288---at the time I was convinced that async readInto was a good solution to our problems for ReadableByteStream, which made me want to align ReadableStream with its own async read.
I think I have a new idea that satisfies our constraints. I go into more detail in https://gist.github.com/domenic/e251e37a300e51c5321f where you can see some evolution going on. The idea is that we revert from .ready to .wait(), and add an optional buffer parameter to .wait(). Here is some sample code from the gist:
I think this idea is pretty nice, for a few reasons:
read(sourceAB, offset, bytesDesired) -> Promise<{ result, bytesRead }>
, this clearly separates supplying a buffer to the stream from getting a chunk from the stream. This kind of cognitive distance between the two operations helps make the transfer process feel less unnatural.It has one downside I want to highlight:
read(sourceAB, offset, bytesDesired) -> Promise<{ result, bytesRead }>
API. This API is very awkward though and I can't see a clear way to redeem it. So I think we'd want a very compelling use case before doing so.What do you guys think? I'd like to get this decided soon since I know there are implementations of ReadableStream under way and, per my long paragraph, our decisions on ReadableByteStream will impact ReadableStream.
@tyoshino @yutakahirano @wanderview @calvaris
The text was updated successfully, but these errors were encountered: