镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

stream.compose does not preserve 'readableObjectMode' from final stream to returned stream #46829

Description

@loganfsmyth

Version

v19.7.0

Platform

No response

Subsystem

No response

What steps will reproduce the bug?

const stream = require("stream");

const s = stream.compose(
  stream.Readable.from("0 1 2 3 4"),
  new stream.Transform({
    readableObjectMode: true,
    transform: function (val, enc, callback) {
      for (const num of val.toString().split(" ")) {
        this.push(`${num}`);
      }
      callback();
    },
  })
);

s.on("readable", () => {
  let data;
  while ((data = s.read()) !== null) {
    console.log("read:", `${data}`);
  }
});
s.on("end", () => {
  console.log("done");
});

How often does it reproduce? Is there a required condition?

No response

What is the expected behavior?

Should output

read: 0
read: 1
read: 2
read: 3
read: 4
done 

What do you see instead?

read: 01234
read: null
done

Additional information

No response

Activity

  1. loganfsmyth commented on Feb 24, 2023

    @loganfsmyth
    ContributorAuthor

    I'm assuming this is just a typo on this line:

    readableObjectMode: !!tail?.writableObjectMode,

  2. climba03003 commented on Feb 25, 2023

    @climba03003
    Contributor

    You should use .on('data') instead of .on('readable').
    readable event and .read consume all the pending data at once.
    So, the output is concatenated string for all 0, 1, 2, 3, 4.

    https://nodejs.org/dist/latest-v18.x/docs/api/stream.html#readablereadsize

    If the size argument is not specified, all of the data contained in the internal buffer will be returned.

  3. loganfsmyth commented on Feb 25, 2023

    @loganfsmyth
    ContributorAuthor

    That's absolutely true for non-object-mode streams, but I'm confident that's not expected for an object mode stream. I think the code above just should be

    -readableObjectMode: !!tail?.writableObjectMode, 
    +readableObjectMode: !!tail?.readableObjectMode, 
  4. benjamingr commented on Feb 25, 2023

    @benjamingr
    Member

    I don't understand, the transform stream needs to be both readable and writable in object mode. Otherwise the returned stream (the one the transform is writing into) isn't in object mode (the return stream isn't in writableObjectMode anyway).

    The example works if you add writableObjectMode: true to the transform stream (or just objectMode: true instead of both).

  5. loganfsmyth commented on Feb 25, 2023

    @loganfsmyth
    ContributorAuthor

    the transform stream needs to be both readable and writable in object mode

    Can you clarify what you mean by that? I know my transform stream could be a writable object stream, but I don't think it's required or expected that anything that is readable-object-mode must be in writable-object-mode. In this case I'm expecting the transform to take in a byte stream and produce and object stream, essentially.

    I'd expect that compose would return a stream that is:

    • writable-object-mode if the first argument is writable-object-mode
    • readable-object-mode if the last argument is readable-object-mode
  6. rluvaton commented on Apr 4, 2023

    @rluvaton
    Member

    I agree with @loganfsmyth and it is expected IMO given that a Transform can get bytes and write object

    "For Duplex streams, objectMode can be set exclusively for either the Readable or Writable side using the readableObjectMode and writableObjectMode options respectively."

    From the Docs

    This logs the data:

    let readInByteWriteInObject = new Transform({
        // reading FROM you in object mode or not
        readableObjectMode: true,
    
        // writing TO you in object mode or not
        writableObjectMode: false,
        transform: function (value, enc, callback) {
            callback(null, {
                data: value
            });
        },
    });
    
    
    
    readInByteWriteInObject.on('data', (data) => {
        console.log(data);
    });
    
    readInByteWriteInObject.write('0 1 2 3 4')

    but this does not:

    let readInByteWriteInObject = new Transform({
        // reading FROM you in object mode or not
        readableObjectMode: true,
    
        // writing TO you in object mode or not
        writableObjectMode: false,
        transform: function (value, enc, callback) {
            callback(null, {
                data: value
            });
        },
    });
    
    
    const s = Readable.from("0 1 2 3 4", {objectMode: false})
        .compose(
            readInByteWriteInObject
        );
    
    s.on('data', (data) => {
        console.log(data);
    });
  7. added a commit that references this issue on Apr 5, 2023
    abb7c4a
  8. added a commit that references this issue on May 2, 2023
  9. added a commit that references this issue on Jul 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    streamIssues and PRs related to Node.js streams.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions