Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

stream.read(0) should not trigger the end event if there is no underlying data #6634

Closed
jonathanong opened this issue Dec 4, 2013 · 5 comments
Labels

Comments

@jonathanong
Copy link

unless you want to undocument it, .read(0) for me is "start getting data from the underlying source but don't consume this stream yet". thus, it shouldn't emit end until .read(n) is called with anything but n === 0.

test case:

var stream = new (require('stream')).Readable
stream.on('end', function () { console.log('end')})
stream._read = function(){}
stream.push(null)
stream.read(0)
// `end` is emitted but should not
stream.read()
// now `end` should be emitted
@trevnorris
Copy link

Thanks.

@isaacs What's your interpretation?

@jonathanong
Copy link
Author

/cc @chrisdickinson

@chrisdickinson
Copy link

Going to bring the current docs in here:

stream.read(0)

There are some cases where you want to trigger a refresh of the underlying readable stream mechanisms, without actually consuming any data. In that case, you can call stream.read(0), which will always return null.

If the internal read buffer is below the highWaterMark, and the stream is not currently reading, then calling read(0) will trigger a low-level _read call.

There is almost never a need to do this. However, you will see some cases in Node's internals where this is done, particularly in the Readable stream class internals.

stream.read(0) is a very delicately-defined case: it depends on one's conception of "data" in the context of streams. Specifically, it hinges on the idea that "end" is not part of the data stream -- it's part of the read mechanism. This definition is unintuitive, since a normal end is usually signified by the stream doing a .push(null) -- which implies that there's a FIFO stack of data held by the stream, at the end of which is now a sort of "EOF" symbol. However, no such symbol exists. As soon as the null is pushed, regardless of the state of the stack of data, the stream is ended, and will emit "end" if read is called and it has no data left. Once a ended stream's read mechanism is activated, it will attempt to consume the data out of its stack. If no data is present, an ended stream's read mechanism will emit "end" -- it's not part of the data stream-to-be-consumed, it's part of the read mechanism.

To clarify between read(0), read(N), and read():

  • read(0) is "start the state machine and advance as if you cannot fulfill the request"
  • read(N) is "start the state machine and advance until you can give me N bytes"
  • read() is "start the state machine and advance until you can give me any bytes you have"

Assuming a (simplified, incorrect) state machine like so:

      yes, return data                 yes, return data
            ^                                 ^
            |                                 |
    no, have X data? -> internal _read -> have X data? -> is eof? -> no, return data or null
            ^              set "ended"                      |                 ^    |
            |             if push(null)                     |                 |    |
            |                                               |                 |    |
            |                                               V                 |    |
      is ended and     ------------------------------> yes, emit end ---------+    |
     have no data?                                                                 |
            ^                                                                      |
            |                                                                      |
neutral -> read(X)                                                                 |
  ^                                                                                |
  |                                                                                |
  +--------------------------------------------------------------------------------+

push(null) is called out-of-band here so the stream is already "ended", and has no data, so it immediately schedules the "end" event.

@jasnell
Copy link
Member

jasnell commented May 28, 2015

@chrisdickinson ... does this need to stay open?

@jasnell
Copy link
Member

jasnell commented Jun 24, 2015

Closing due to lack of further activity. Can reopen if necessary.

@jasnell jasnell closed this as completed Jun 24, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants