-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
Using for await...of
with break
to read from a stream
#46717
Comments
@nodejs/stream @mcollina wdyt? |
Not exactly related to the underlying issue, but we have a built-in module to achieve what the code snippet on the OP is trying to do: import readline from 'node:readline/promises';
const rl = readline.createInterface({ input: process.stdin })[Symbol.asyncIterator]();
const readLine = async () => {
const { done, value } = await rl.next();
if (done) throw new Error('no more data');
return value;
}; |
@aduh95 Actually, the problem that I have is not related to |
This is working as expected. By default, doing a |
I think @mcollina, what @Babak-Gholamzadeh means is that no error should happen, when he stops consuming the stream from for-await-of |
Breaking from a for await closes the iterator which destroys the stream so you don't leak resources. This is intentional in the design of async generators and how async iterators generally behave in JS. In order to enable your use case - we've added |
I also think it's fine to destroy the stream without an AbortError (probably) but I recall objections to that last time we discussed it. |
Actually I think there is a third case here which we haven't considered. I'm out travelling atm but will get back to this. |
Destroying the stream on But as @tonivj5 mentioned too, the problem is with throwing the error. Also, using the |
I'm a little confused, the following does work as expected, i.e. no error. for await (const z of Readable.from([1,2,3,4])) {
break
} Is this a problem only with stdin? Does anyone have a minimal repro? |
@ronag I was able to reproduce: const common = require('../common');
const { Readable } = require('stream');
{
async function* generate() {
yield 'something';
}
const abortedStream = Readable.from(generate());
abortedStream.on('error', common.mustNotCall());
(async () => {
for await (const chunk of abortedStream) {
break;
}
})().then(common.mustCall());
}
the async IIFE does not return rejected promise but the error event omits though... |
Actually, @ronag your example is ok but you didn't listen to error events const abortedStream = Readable.from([1,2,3,4]);
abortedStream.on('error', common.mustNotCall());
(async () => {
for await (const chunk of abortedStream) {
break;
}
})().then(common.mustCall()); does emit:
|
@benjamingr is this the expected behavior? if we want it to not emit an abort error by default when destroying a stream we should remove this line: node/lib/internal/streams/destroy.js Line 305 in 3a648af
but I'm afraid it's a breaking change and not the wanted behavior. if only on break from iterable we should think of another approach. maybe a better way is destroy without an error (why destroy must have an error anyway and not be treated as finish in case node/lib/internal/streams/readable.js Line 1149 in 3a648af
|
Because interrupting a flowing stream is an error situation for any of the other consumer. Note that you can "observe" all the data flowing via asynciterator by adding an on('data') listener. The error emitted in this case is to let them know what happened. As said before, you can customize this behavior by calling the |
Version
v18.14.1
Platform
Microsoft Windows NT 10.0.19045.0 x64"Microsoft Windows NT 10.0.19045.0 x64
Subsystem
streams
What steps will reproduce the bug?
I'm trying to read from
process.stdin
by usingfor await
until I get\n
(as you can see in the code snippet blow):But when it reaches to
break
, it will throw an error in the stream.The output of my log:
I've also tried to read from a file stream like this and got the same error.
I got the same error on a Mac machine as well.
How often does it reproduce? Is there a required condition?
Always
What is the expected behavior?
I don't know what exactly the expected behavior should be here, but throwing an error doesn't make sense to me
What do you see instead?
Additional information
No response
The text was updated successfully, but these errors were encountered: