-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
Node Streams constructed from Web Streams not emitting the 'end' event #46149
Comments
You still have something left inside the import { ReadableStream } from 'node:stream/web';
import { Readable } from 'node:stream';
const stream = Readable.fromWeb(new ReadableStream({
start(controller) {
controller.enqueue('foo'); // 1. ['foo']
controller.close(); // 3. [null]
},
}));
// since it is once only. null is left behind for notify the stream is ended.
stream.once('readable', () => {
console.log(stream.read()?.toString()); // 2. [ ]
});
// if we use on, the null one will be read and properly close
// stream.on('readable', () => {
// console.log(stream.read()?.toString()); // 2. [ ] 4. [ ]
// });
stream.on('end', () => {
console.log('ended');
}); |
Hi @climba03003 thank you so much for the explanation, mistake on my side for using import { ReadableStream } from 'node:stream/web';
import { Readable } from 'node:stream';
const stream = Readable.fromWeb(new ReadableStream({
start(controller) {
controller.enqueue('foo');
controller.close();
},
}));
stream.on('readable', () => {
console.log(stream.read()?.toString());
});
stream.on('end', () => {
console.log('ended');
}); gives the output as foo
undefined
ended whereas running this code with Readable import { Readable } from 'node:stream';
const stream = new Readable({
read() {
this.push('foo');
this.push(null);
}
});
stream.on('readable', () => {
console.log(stream.read()?.toString());
});
stream.on('end', () => {
console.log('ended');
}); gives the output foo
ended could the undefined that comes when using ReadableStream be an inconsistency/bug? |
This is how import { Readable } from 'node:stream';
let num = 0
const stream = new Readable({
read() {
// should be promise in ReadableStream
// but we use nextTick to do the same effect
if(num === 0) {
process.nextTick(() => {
this.push('foo') // 1. ['foo']
})
} else {
process.nextTick(() => {
this.push(null) // 3. [null] - here is the one left behind
})
}
num++
}
});
stream.once('readable', () => {
console.log(stream.read()) // 2. [ ]
});
stream.on('end', () => {
console.log('ended');
}); |
Understood! So I guess the promise based behaviour of |
Also if I understand correctly pushing null should immediately trigger end of stream as per the code over here? |
Partially, Yes. It is how
Personally, no. It is a misconception of code flow. But it require the core member to identify if it is a bug.
It would not accept more |
Understood thank you so much @climba03003! |
I'm a bit confused, this seems like a bug to me: const { Readable, PassThrough } = require('stream')
function getStream() {
const body = new PassThrough();
body.push('test');
body.push(null);
return body;
}
async function main() {
const nodeStream = getStream()
nodeStream.on('data', console.log)
await new Promise(resolve => nodeStream.once('end', resolve))
console.log('nodeStream done')
const wrappedNodeStream = Readable.fromWeb(Readable.toWeb(getStream()))
wrappedNodeStream.on('data', console.log)
wrappedNodeStream.on('end', () => console.log('end')) // This event is never emitted!
}
main() The above code produces:
i.e. the 'end' event from the double-wrapped stream is never emitted. How am I supposed to detect the end of such a stream? A |
I think this is a bug in const { Readable, PassThrough } = require('stream')
function getStream() {
const body = new PassThrough();
body.push('test');
body.push(null);
return body;
}
async function main() {
const webStream = Readable.toWeb(getStream())
for await (const v of webStream) console.log(v)
console.log('here') // This line is never printed!
}
main() The |
Your problem is that you are using
|
@climba03003 yeah, that was it. Passing {allowHalfOpen: false} to PassThrough fixes the issue. |
Version
v20.0.0-pre
Platform
Darwin MacBook-Pro.local 22.1.0 Darwin Kernel Version 22.1.0: Sun Oct 9 20:14:54 PDT 2022; root:xnu-8792.41.9~2/RELEASE_X86_64 x86_64
Subsystem
streams
What steps will reproduce the bug?
following is the code I tried to run
How often does it reproduce? Is there a required condition?
Always
What is the expected behavior?
What do you see instead?
foo
Additional information
This found while trying to work on #39316
The text was updated successfully, but these errors were encountered: